==、equals、hashcode、hashset判重
0. 哈希码值hashCode
哈希码值(hashCode),也称散列码值是一个通过哈希散列算法得到的数据值,在java中可通过int hashCode()返回某对象的哈希码值。
这个哈希码的作用是确定该对象在哈希表中的索引位置。hashCode() 定义在JDK的Object.java中,这就意味着Java中的任何类都包含有hashCode()函数。
hashCode有以下特点:
- 哈希散列算法对于同一个对象在同一次程序执行过程中,调用多次hashcode方法得到的值必须是一致的;
- 哈希散列算法对于不同对象计算出的哈希码结果相同的概率非常小,可认为是一一对应的单射。即:每个对象的哈希码值都不同
- 因着以上两点可以判断两个对象是否是同一个对象。
hashCode的计算方式:
- 字符串:\(s[0]*31^{(n-1)}+s[1]*31^{(n-2)}+...+s[n-1]^0\)
其中s[i]是字符串的第i个字符,n是字符串长度。空字符串的哈希值为0; - 八大基本数据类型哈希值是固定:
- 整型:就是值本身
- 浮点型:通过固定的计算模式计算得到
- 字符型:是该字符对应的ASCII码值
- 布尔型:哈希值是固定的 true:1231 false:1237
1. ==和equals
== : 它的作用是判断两个对象的地址是不是相等。即,判断两个对象是不是同一个对象。
- 基本数据类型 == 比较的是值。
- 引用数据类型 == 比较的是内存地址
equals() : 它的作用也是判断两个对象的地址是不是相等。但它一般有两种使用情况:
- 情况1:类没有覆盖 equals() 方法。则通过 equals() 比较该类的两个对象时,等价于通过“==”比较这两个对象。(object的equals方法是比较的对象的内存地址。)
- 情况2:类覆盖了 equals() 方法。一般,我们都覆盖 equals() 方法来两个对象的内容相等;若它们的内容相等,则返回 true (即,认为这两个对象相等)。此时,标准流程如下:
- 先判断地址值是否相同,同则直接true。
- 判断传入参数是否为null,是则直接false。
- 判断两个对象是否同一类型(利用getClass()),如果不是则直接false。
- 进行每个属性的一一判断
- 基本数据类型用==
- 引用数据类型用equals
//重写equals案例
class Person{
String name;
int age;
public boolean equals(Object obj){
if(this==obj) return true;//同一个对象
if(obj==null) return false;//空指针
if(this.getClass()!=obj.getClass()) return false;
//在方法参数中向上造型了,隐蔽了其中的子类属性
//必须要再向下造型,方可调用
Person person = (Person)obj;
//比较第一个属性
if(this.name==null){
if(person.name!=null){
return false;
}
}else if(this.name.equals(person.name)){
return false;
}
//比较第二个属性
if(this.age!=person.age) return false;
//到此为止,必然相同
return true;
}
}
【注】地址值实际就是该对象的哈希码值转为16进制的字符串形式。
2. HashCode与equals的相关规定
- 如果两个对象相等,则hashcode一定也是相同的。
- 两个对象相等,对两个对象分别调用equals方法都返回true
- 两个对象有相同的hashcode值,它们也不一定是相等的(虽然概率极小)
- hashCode() 的默认行为是对堆上的对象产生独特值。如果没有重写 hashCode(),则该 class 的两个对象无论如何都不会相等(即使这两个对象指向相同的数据)
3.【引】HashSet如何检查重复?
当把对象加入 HashSet 时,HashSet 会先计算对象的 hashcode 值来判断对象加入的位置,同时也会与其他已经加入的对象的 hashcode 值作比较,如果没有相符的hashcode,HashSet会假设对象没有重复出现。
但是如果发现有相同 hashcode 值的对象,这时会调用 equals()方法来检查 hashcode 相等的对象是否真的相同。如果两者相同,HashSet 就会覆盖。如果不同的话,就会重新散列到其他位置。