如果只看jdk文档对于新手来说,很难理解java为什么要求重写这两个方法。在面向对象的世界里,如何确定两个对象是否相等(或者说逻辑上相等)是要解决的一个问题,Java通过equal方法来确定两个对象是否相等。Java对象的创建是在堆上进行的,如果用new关键字创建一个类的两个对象,java里时如何判定这两个对象是否相等的呢?
举个例子:
class Employee {
Integer id;
public void setId(Integer id) {
this.id = id;
}
}
假如一家公司认为只要员工编号相同就是同一个员工(虽然有点不太合理,但没想到更像样的例子)。接下来,如下代码来判断员工是否是同一个人
Employee e1 = new Employee();
Employee e2 = new Employee();
e1.setId(1);
e2.setId(1);
System.out.println(e1.equals(e2));
很遗憾,这段代码的输出为false。
为了达到判定这样的两个员工是同一个员工,需要重写equals方法。
class Employee {
Integer id;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
@Override
public boolean equals(Object o) {
if(o == null) {
return false;
}
if (o == this) {
return true;
}
if (getClass() != o.getClass()) {
return false;
}
Employee e = (Employee) o;
return (this.getId() == e.getId());
}
}
运行如下的测试方法
Employee e1 = new Employee();
Employee e2 = new Employee();
e1.setId(1);
e2.setId(1);
System.out.println(e1.equals(e2));
Set<Employee> employees = new HashSet<Employee>();
employees.add(e1);
employees.add(e2);
System.out.println(employees);
System.out.println(e1.equals(e2));
程序运行结果如下:
true
[com.shunwang.meteor.example.Employee@dc8569, com.shunwang.meteor.example.Employee@1bab50a]
第一个运行结果是正确了,但第二个竟然输出了两个,Java中Set是能去重的,那问题出在哪里呢?
原来,Java中对于HashSet的存储利用了HashMap,而HashMap是采用数组加链表的数据结构的(如果不清楚请读一下HashMap的源代码,如果了解HashMap的存储结构,此问题就很好理解了)。HashMap首先通过对象的hashcode计算存储位置(如果hash冲突,该位置用一个链表解决冲突),再比较元素的值。上述问题早于未重写对象的hashcode方法(默认继承Object,默认返回对象的内存地址编号)。修改代码如下:
class Employee {
Integer id;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
@Override
public boolean equals(Object o) {
if(o == null) {
return false;
}
if (o == this) {
return true;
}
if (getClass() != o.getClass()) {
return false;
}
Employee e = (Employee) o;
return (this.getId() == e.getId());
}
@Override
public int hashCode() {
final int code = 31;
int result = 1;
result = code * result + getId();
return result;
}
}
执行结果:
true
[com.shunwang.meteor.example.Employee@20]
如果理解这两个方法的用处,那些描述文章中描述的各种"性"就好理解了。