浅谈equals() 与 hashcode()

        项目闲暇,读书所获。

        equals()是根类Object中的方法。源码如下:

public boolean equals(Object obj) {
    return (this == obj);
}

        默认的equals()方法,直接调用==,比较对象在JVM中的地址。

        再来谈谈和equals()方法较为相似的hashcode()方法:

        (1)hashcode如何形成?

        hashcode代表对象在hash表中的位置,通过对象的物理地址(存放在内存中的地址)转换成一个整数,然后该整数通过hash函数的算法就得到了hashcode。

        (2)hashcode有什么作用?

        hashcode的存在主要是为了查找的快捷性。hashcode是用来在散列存储结构中确定对象的存储地址的(用hashcode来代表对象在hash表中的位置)。java集合中有一类是set,特点是元素无序,但元素不可重复,判断重复的方法是Object.equals()方法。元素很多时,就需要比较很多次,效率较低。但是,当先调用元素的hashCode()方法时,就能定位到它对应放置的物理存储位置,如果这个位置上没有元素,可直接放置,如果有元素,就调用它的equals()方法与他们进行比较,出现相同的,就不存储,如果不相同就散列其他的地址。那么采用hashCode(),比较次数会大大减少,效率会提高。

        所以,可以得出,如果两个对象相同,那么他们的hashcode值一定相同;如果两个对象的hashcode值不同,那么两个对象肯定不相等。当需要大量并且快速的对比的话,首先用hashCode()去对比,如果hashcode不一样,那么两对象肯定不一样,也就没必要再去用equals()进行比较了,如果两对象的hashcode值一样,那么再用equals()去进行比较,如果equals()比较下来也相同,那么两对象就真的相同了。这样不仅保证了对比的准确性,更重要的是效率也大大增加。

        hashCode()也是根类Object中的方法,由上面所述可以看出,两者的作用是大致一样的,都是实现对象的对比。但是在实际情况下,由于我们在一个类中new两个对象,其在内存里的地址肯定不同,两对象的对比就没有什么意义了。所以equals()和hashCode()经常要被重写。

        下面用具体的例子来重写的equals()和hashCode()方法。

扫描二维码关注公众号,回复: 4464367 查看本文章

        重写equals()方法:

        定义Person类,在其中重写equals()方法。

public class Person {
	private String name;
	public Person(String name){
		this.name = name;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	@Override
	public boolean equals(Object obj){
		if(obj instanceof Person){
			Person person = (Person) obj;
			return name.equals(person.getName()) ;
		}
		return false;
	}	
}

        定义EqualsTest.java,测试查看结果。

public class EqualsTest {
	public static void main(String[] args) {
		Person p1 = new Person("张三");
		Person p2 = new Person("张三");
                System.out.println(p1.equals(p2));
                System.out.println(p1.hashCode());
                System.out.println(p2.hashCode());
    }
}

        输出结果为

                           

        可见,两对象相同,其对应的hashcode也不一样。

        在散列表中,如果要判断两个对象是否相等,除了要覆盖equals()方法,还要覆盖hashCode(),否则equals()方法无效。我们将两个Person对象放入HashSet中,并观察其输出结果。

public class EqualsTest {
	public static void main(String[] args) {
		Person p1 = new Person("张三");
		Person p2 = new Person("张三");
		
		HashSet<Person> set = new HashSet<Person>();
		set.add(p1);
		set.add(p2);
		for(Person person : set){
		    System.out.print(person.getName()+" ") ;
		}    
		System.out.println();
                System.out.println(p1.equals(p2));
                System.out.println(p1.hashCode());
                System.out.println(p2.hashCode());
    }
}

        输出结果为

                          

        我们只是重写了equals()方法,但是对于一个HashSet来讲,元素是不允许重复的,出现这种现象的原因是虽然p1和p2的内容相同,但是hashcode不一样,所以HashSet在添加元素时,认为两者并不相等,HashSet会将它们存储在不同的位置,依然可以添加成功。

        当我们同时覆盖equals()和hashCode()方法时,

public class Person {
	private String name;
	public Person(String name){
		this.name = name;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
		
	@Override
	public boolean equals(Object obj){
		if(obj instanceof Person){
			Person person = (Person) obj;
			return name.equals(person.getName()) ;
		}
		return false;
	}
	@Override
	public int hashCode(){
		final int prime = 31;
		int result = 1;
		result = prime * result + ((name == null) ? 0 : name.hashCode());
		return result;
	}
}

        输出结果为

                          

        此时HashSet没有重复的元素,符合set的特性。HashSet集合判断两个元素相等的标准是两个对象通过equals()方法比较相等,并且两个对象的hashCode()方法返回值也相等。

日ji

猜你喜欢

转载自blog.csdn.net/jsh306/article/details/84944532