我们一般使用equals都是为了比较对象的内容,而Object里面的equals方法却是比较对象的引用,如下:
public boolean equals(Object obj) {
return (this == obj);
}
所以当我们想要比较的是对象的内容时,需要重写equals方法,假设User类中有String name , int age 两个字段,用eclipse自动生成的
equals方法写法如下:
public boolean equals(Object obj) {
if (this == obj)
return true; // 两者引用相等则是同一个对象故内容相等
if (obj == null)
return false;
if (getClass() != obj.getClass()) // 两者的类不相等,则内容不可能相等
return false;
User other = (User) obj; // 将其向下转型
if (age != other.age) // 下面就是开始比较内容
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
一个测试用例
public class Test {
public static void main(String[] args) {
User user1 = new User();
User user2 = new User();
System.out.println(user1.equals(user2));
}
}
打印true。如果把User类重写的equals方法去掉,此时user1.equals()调用的是Object类的equals方法,比较的是引用而不是内容,user1和user2的引用明显不同,故打印false。常用的equals方法比较的是对象的内容,即对象要属于同一个类且字段属性相等才相等。
HashCode主要用于类集框架。假设我们对一个类不重写hashCode方法,对象调用hashCode方法时则调用的是Object类的hashCode方法:
public native int hashCode();
生成的散列值都是不相同的,而如果我们重写了hashCode方法,对于内容相同的对象则可以生成相同的散列值。
至于hashCode方法写法,我们一般也不需要记住,直接用工具生成就好了。
测试用例:
public class Test {
public static void main(String[] args) {
// TODO 自动生成的方法存根
HashSet<User> set = new HashSet<>();
User user1 = new User("leelit", 21);
User user2 = new User("leelit", 21);
User user3 = new User();
System.out.println(user1.hashCode());
System.out.println(user2.hashCode());
System.out.println(user3.hashCode());
set.add(user1); // 添加user1和user2
set.add(user2);
System.out.println(set.size());
HashMap<User, String> map = new HashMap<>();
map.put(new User("lina", 21), "value");
System.out.println(map.get(new User("lina", 21)));
}
}
打印结果:
-1106625705
-1106625705
961
1
value
把User类重写的hashCode方法去掉后打印:
31168322
17225372
5433634
2
null
没有重写hashCode方法时:两个对象即使内容相等,也生成不同的散列值,所以都可以add进set里面去,我们知道HashSet是不可以有重复的元素的,所以这就是为什么必须要重写hashCode的原因;同理对于HashMap虽然put和get的是同样的key,但由于散列值不同,而被视作了不同的key,所以无法取出来。
重写hashCode方法后,两个相等的对象会生成相同的散列值。