黑马程序员技术交流社区

标题: 笔试:覆盖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