黑马程序员技术交流社区
标题: 笔试:覆盖equals时总要覆盖hashCode [打印本页]
作者: 奥斯托洛夫斯基 时间: 2018-9-6 15:22
标题: 笔试:覆盖equals时总要覆盖hashCode
在每个覆盖equals方法的类中,也必须覆盖hashcode方法,如果不这么做,就会违反Object.hashCode 的通用约定,从而导致该类无法结合散列的集合一起正常运作,这样的集合包括HashMap,HashSet和Hashtable.
jdk6中Object规范:
1、在应用程序的执行期间,只要对象的equals方法的比较操作所用到的信息没有修改,那么对着同一个对象调用多次,hashcode方法都必须始终如一的返回同一个整数。在同一个应用程序的多次执行过程中,每次执行返回的整数可以不一致。
2、如果两个对象根据equals(Object)方法比较是相等的,那么调用着两个对象中任意一个对象的hashcode方法都必须产生同样的整数结果。
3、如果两个对象根据equals(Object)方法比较是不相等的,那么调用这两个对象中任意一个对象的hashcode方法,则不一定要产生不同的整数结果。但是程序员应该知道,给不相等的对象产生截然不同的整数结果,有可能提高散列表(hash table)的性能。
因为没有覆盖hashCode方法违反了第二条,相等的对象必须具有相等的散列码(hash code)。
public class Student { private String name ; private int age; private String sex; private long score; private List food; private Map<String ,String> clothes; private String[] others; private kid kid; public kid getKid() { return kid; } public void setKid(kid kid) { this.kid = kid; } public String[] getOthers() { return others; } public void setOthers(String[] others) { this.others = others; } public Map<String, String> getClothes() { return clothes; } public void setClothes(Map<String, String> clothes) { this.clothes = clothes; } public List getFood() { return food; } public void setFood(List food) { this.food = food; } public long getScore() { return score; } public void setScore(long score) { this.score = score; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } public Student(String name, int age, String sex) { this.name = name; this.age = age; this.sex = sex; } @Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Student other = (Student) obj;
if (age != other.age)
return false;
if (clothes == null) {
if (other.clothes != null)
return false;
} else if (!clothes.equals(other.clothes))
return false;
if (food == null) {
if (other.food != null)
return false;
} else if (!food.equals(other.food))
return false;
if (kid == null) {
if (other.kid != null)
return false;
} else if (!kid.equals(other.kid))
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
if (!Arrays.equals(others, other.others))
return false;
if (score != other.score)
return false;
if (sex == null) {
if (other.sex != null)
return false;
} else if (!sex.equals(other.sex))
return false;
return true;
}
}
只覆盖了equals方法没有覆盖hashCode方法,测试代码:
public class Demo { public static void main(String[] args) { Map<Student ,String> map = new HashMap(); map.put(new Student("一号" ,18 , "男") , "测试一号"); String string = map.get(new Student("一号" ,18 , "男")); System.out.println(string); }}
结果:
由于没有覆盖hashCode方法,从而导致两个相等的实例具有不相等的代码,违反了hashCode约定,其中的put方法将对象放在一个散列桶中(hash bucket)中,get方法却在另一个散列桶中查询这个对象,即使这两个实例正好被放在同一个散列桶,get方法也必定会找到这个对象。此时添加一个hashCode方法:
结果:
添加了合法的hashCode方法,就确保了相等的对象总是具有同样的散列码。但是由于固定了返回值,使得每个对象都具有相同的散列码,导致每个对象都被映射到同一个散列桶中,是散列表退化为链表(linked list)。使得本该线性时间运行的程序变成了平方级时间在运行,对于大规模的散列表而言,这会关系扫散列表是否正常工作。
散列码的理想计算方式:
各种数据类型的散列码的计算方式,详情参考每种数据类型中源码中的hashCode方法。
作者: TomGe 时间: 2018-9-6 17:27
66666
作者: 靖研 时间: 2018-9-6 17:28
6666
作者: 鸟语花香 时间: 2018-9-6 17:29
作者: hguilin 时间: 2018-9-6 17:29
666666666666
作者: 合肥黑马9期 时间: 2018-9-6 17:29
作者: 黑马啸西风 时间: 2018-9-6 17:30
作者: 奥斯托洛夫斯基 时间: 2018-9-6 17:31
作者: 奥斯托洛夫斯基 时间: 2018-9-6 17:31
作者: O-limin 时间: 2018-9-6 17:31
作者: 我开心你随意 时间: 2018-9-6 18:06
作者: 天亮1 时间: 2018-9-6 18:14
欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) |
黑马程序员IT技术论坛 X3.2 |