深入理解hashCode

1、hashCode的概念

(1)hashCode方法是Object类的方法,在Java里所有类都默认继承Object类,即所有类都有hashCode方法。

(2)hashCode是jdk根据对象的存储地址算出来的一个int数字,即对象的哈希码值,代表了该对象在内存中的存储地址

2、hashCode的作用

2.1、hashCode查找的快捷性

hashCode的存在主要是用于查找的快捷性,如HashTable、HashMap等,hashCode用来在散列存储结构中确定对象的存储地址(是存储地址)。

2.2、HashSet不允许重复是如何实现的

比如,大家都知道HashSet是不允许重复的,HashSet有100个元素了,这时再add一个新元素。

(1)如果没有hashCode

就需要迭代100次,调用100次equals方法来判断该HashSet里是否已经存在这个新添加的元素。可想而知,效率是很低的。

(2)如果有hashCode

向HashSet添加一个新元素时,HashSet首先会调用hashCode方法,这样就可以定位到它的存储位置,若该处没有元素,则直接保存。如果该处已经有元素存在,就调用equals判断这两个元素内容是否相同,相同则不存,不同则散列到其它位置。这样处理,当我们向HashSet插入大量元素的时候就可以大大减少调用equals方法的次数,提高了效率。

2.3、HashSet集合和hashCode方法的代码示例

import java.util.HashSet;

public class Person {

    private int id;
    private String name;
    
    public Person(int id, String name) {
        super();
        this.id = id;
        this.name = name;
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + id;
        result = prime * result + ((name == null) ? 0 : name.hashCode());
        
        //用于查看hashCode方法什么时候被调用,以及被调用的次数
        System.out.println("hashCode被调用, hashCode=" + result);
        
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        
        //用于查看equals方法什么时候被调用,以及被调用的次数
        System.out.println( "equals被调用了" );
        
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Person other = (Person) obj;
        if (id != other.id)
            return false;
        if (name == null) {
            if (other.name != null)
                return false;
        } else if (!name.equals(other.name))
            return false;
        return true;
    }
    
    public static void main(String[] args) {
        HashSet<Person> personHashSet = new HashSet<Person>();
        personHashSet.add(new Person(1, "张三"));
        personHashSet.add(new Person(2, "李四"));
        personHashSet.add(new Person(1, "张三"));
        System.out.println("personHashSet的长度是" + personHashSet.size());
    }
    
} 
hashCode被调用, hashCode=775881
hashCode被调用, hashCode=843084
hashCode被调用, hashCode=775881
equals被调用了
personHashSet的长度是2

每次向personHashSet添加一个Person时,都会调用hashCode方法,这样就可以直接定位该Person所存储的位置,若该处没有其它Person,则直接保存。若该处已经有Person存在,就调用equals方法来判断两个Person是否相同,相同则不存,不同则散列到其他位置。示例代码里,向personHashSet添加新元素时,hashCode方法无论如何都会被调用,所以hashCode方法被调用了三次。第1个Person和第3个Person的hashCode是相同的,添加第3个Person时才会去调用equals方法,所以equals方法被调用了一次。equals为true,相同则不存,所以personHashSet的长度是2。

(注:HashSet更详细的解读,会出现在本人后面的博文中,这里就不喧宾夺主本文的主题了。)

3、hashCode和equals的关系

(1)equals相等,hashCode一定相等。

(2)equals方法被重写,那么hashCode方法也应该被重写,并且产生hashCode使用的对象(类里面的属性),一定要和equals方法中使用的一致。

(3)hashCode相等,equals不一定相等。只能说明这两个对象在散列存储结构里(如Hashtable)“存放在同一个蓝子里”。

原文地址:https://www.cnblogs.com/onezg/p/8948767.html