重写hashcode

正确重写hashCode的办法

[1]. hashCode重写成相同的值缺点

将全部对象的hashCode都返回同样的值是不科学的。好比a1和a3这两个根本不一样的对象,就没有必要去比较equals,增长无谓的计算量因此应该对象自己的内容 (属性)来重写hashCode。

一旦两个对象内部不同,就直接断定出hashCode不同不用再调用equals进行比较

[2]. 正确书写hashCode的办法:

【原则】按照equals( )比较两个对象是否一致条件用到的属性重写hashCode()

{1}. 经常使用的办法就是利用涉及到的的属性进行线性组合

{2}. 线性组合过程当中涉及到的组合系数自定义便可。

注意,拼接以后的数值不能超过整形的表达范围。

{3}. 公式:属性1int形式+ C1*属性2int形式+  C2*属性3int形式+ …

【技巧】属性是引用类型的时候,若是已经重写过hashCode(),那么这个引用属性的int形式就是直接调用属性已有的hashCode值。

最典型的就是这个属性是字符串类型的,String类型已经重写了hashCode()方法,因此直接拿来使用便可。

class Person{
    private String name;
    private int age;
   
    public static void sop(Object o){
        System.out.println(o);
    }
 
    public Person(String name, int age){
        this.name =name;
        this.age =age;
    }
 
    public void setName(String name){
        this.name =name;
    }
   
    public String getName(){
        return this.name;
    }
 
    public void setAge(int age){
        this.age =age;
    }
 
    public int getAge(){
        return this.age;
    }
 
    public String toString(){
        return this.name+"::"+this.age;
    }
 
    //equals已经重写
public boolean equals(Object obj){
if(!(obj instanceof Person)){
            return false;
        }
   
        Person p =(Person)obj;
 
        //用来查看equals方法是否被调用
        sop(this.name +".......equals......."+ p.name);
        //认为名字相同而且年龄同样大的两个对象是一个
return this.name.equals(p.name) && this.age == p.age;
}
}

(2). 将hashCode()重写成相同的值-----解决HashSet中重复添加java

[1]. 问题:内容相同可是地址不一样自定义对象如何避免重复的内容添加到HashSet中?this

【解决办法】必须重写hashCodeequals两个方法spa

{1}. 此时根据底层哈希表的存储方式:哈希表会将具备相同哈希值的元素依次顺延。code

{2}. hashCode值相同,HashSet在存储对象的时候,equals方法就会起做用orm

{3}. 示例代码:为Person类重写以下的hashCode代码对象

public int hashCode(){  内存

    System.out.println(this.name +"...hashCode");  字符串

    return 60;  get

}  hash

这样,每个Person对象都具备相同的哈希值。

打印结果:

HashSet添加过程分析】

【1】a1率先存入HashSet中

添加的时候,调用一次a1的hashCode方法,打印一次a1...hashCode。因为开始HashSet中没有内容,因此没有调用a1的equals方法。

内存图以下:


 

【2】当a2要存入HashSet的时候,HashSet首先调用a2的hashCode方法,此时打印出a2...hashCode。发现a2的hashCode也是0x3c和a1的地址值都是同样的,此时要和a1进行内容比较,打印出a2.......equals.......a1。可是发现name和age都不同,因此equals返回false。此时HashSet就将这个a2存到集合中来。

内存图以下:


 

【3】当a3要存入HashSet的时候,HashSet首先调用a3的hashCode方法,查看有没有地址相同的元素,此时打印出a3...hashCode。此时集合中已经存在两个元素a1和a2,发现a3的hashCode也是0x3c和a一、a2的地址值都是同样的,此时要一一和这些对象的内容进行比较。

       当a3和a2的进行比较时,a3的equals方法被调用,打印出a3.......equals.......a2。 比较发现a3和a2是地址相同可是内容不一样的元素。

    a3再和a1进行比较,a3的equals方法再次被调用,打印出a3.......equals.......a1。

比较发现a3和a1仍然是地址相同可是内容不一样的元素。

a3就被认为是集合中之前并不存在的元素,因此仍然被添加进来。

内存图以下:


 

【4】当运行到第二个a2要添加进来的时候,先调用hashCode,因此立刻打印a2...hashCode。

可是发现,和a2 hashCode相同的元素有a一、a2和a3。这个a2要和集合中的a一、a2和a3都作内容上是否相同的比较。

    a2先比较集合中的a3,调用a2的equals方法,打印出a2.......equals.......a3。

位置相同,可是内容不一样。

    a2再比较集合中的a2,调用a2的equals方法,打印出a2.......equals.......a2。

可是发现二者内容、地址均相同,是重复的元素不能加到集合中来,因此没有必要再把这个a2和集合中的a1进行比较。因此没有打印a2.......equals.......a1


 

(3). 正确重写hashCode的办法

[1]. hashCode重写成相同的值缺点

将全部对象的hashCode都返回同样的值是不科学的。好比a1和a3这两个根本不一样的对象,就没有必要去比较equals,增长无谓的计算量因此应该对象自己的内容 (属性)来重写hashCode。

一旦两个对象内部不同,就直接断定出hashCode不同不用再调用equals进行比较

[2]. 正确书写hashCode的办法:

【原则】按照equals( )比较两个对象是否一致条件用到的属性重写hashCode()

{1}. 经常使用的办法就是利用涉及到的的属性进行线性组合

{2}. 线性组合过程当中涉及到的组合系数自定义便可。

注意,拼接以后的数值不能超过整形的表达范围。

{3}. 公式:属性1int形式+ C1*属性2int形式+  C2*属性3int形式+ …

【技巧】属性是引用类型的时候,若是已经重写过hashCode(),那么这个引用属性的int形式就是直接调用属性已有的hashCode值。

最典型的就是这个属性是字符串类型的,String类型已经重写了hashCode()方法,因此直接拿来使用便可。

e.g. 分析案例

这个例子中,重写的equals方法中是经过name和age来断定两个对象是否一致的。因此,就经过Person的这两个属性name和age的线性组合来获取这个Person的hashCode值。注意到name是String类型的,因此,能够调用name的hashCode()来直接获取name对应的int值。

这里重写的hashCode方法是:

public int hashCode(){

    sop(this.name +"......hashCode");

    return this.name.hashCode() + 29*age;

}

打印结果:

相关文章
相关标签/搜索