hashCode()
和equals()
及==
Java的约定-《算法4》摘录
每种数据类型都需要相应的散列函数,于是Java令所有数据类型都集成了一个能够返回一个32比特整数的hashCode()方法. 每一种数据类型的hashCode()
方法都必须和equals()
方法一致.
-
如果
a.equals(b)
返回true
, 那么a.hashCode()
的返回值必然和b.hashCode()
的返回值相同. -
如果两个对象的
hashCode()
方法的返回值不同, 那么我们就知道这两个对象是不同的. -
如果两个对象的
hashCode()
方法的返回值相同, 这两个对象也有可能不同, 还需要使用equals()
方法进行判断. -
如果要为自定义的数据类型定义散列函数, 需要同时重写
hashCode()
和equals()
方法. 默认的散列函数会返回对象的内容地址, 但这只适用很少的情况. Java为很多常用的数据类型重写了hashCode()
方法(包括String、Integer、Double、File和URL
).
==
比较符号:
- 对于8中基本的数据类型, 比较的是变量所对应内存存储的数值
- 对于指向对象的变量, 比较的也是变量所对应内存存储的数值(即指向的对象占用堆内存的首地址), 也就是比较变量是否指向同一个对象.
equals()
:
-
equals
方法时用于比较两个独立对象的内容是否相同, 需要为类重写equals
方法. - 如果一个类没有定义自己的
equals
方法, 它默认的equals
方法就是从Object
继承来的equals
方法, 相当于==
操作符. 也就是在比较两个变量指向的对象是否为同一个对象, 这时候使用equals和使用==
会得到相同的结果. 如果编写的类希望能够比较该类创建的两个实例对象的内容是否相同, 那么必须覆盖equals
方法.
String
类中的equals
方法:
public boolean equals(Object anObject) {
if (this == anObject) { //如果指向的是同一个地址,那内容肯定相同
return true;
}
if (anObject instanceof String) { // 地址不同时比较内容是否相同
String anotherString = (String) anObject; // 判断是否为String类
int n = value.length;
if (n == anotherString.value.length) {
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
while (n-- != 0) {
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}
}
hashCode()
-
默认情况下,
Object
中的hashCode()
返回对象的32位jvm地址. 也就是说如果对象不重写该方法, 则返回相应对象的32位jvm内存地址. -
当
equals
方法被重写时, 通常有必要重写hashCode
方法, 以维护hashCode
方法的常规协定, 协定声明相等对象必须具有相等的哈希码. -
String
类中的hashCode
:
public int hashCode() {
int h = hash; //Default to 0 ### String类中的私有变量,
if (h == 0 && value.length > 0) { //private final char value[]; ### Sting类中保存的字符串内容的的数组
char val[] = value;
for (int i = 0; i < value.length; i++) {
h = 31 * h + val[i];
}
hash = h;
}
return h;
}
-
举例:
- 未重写
hashCode
时:
import java.util.HashMap; public class Cat { private String color; public Cat(String color) { this.color = color; } public boolean equals(Object obj) { if (obj == null) { return false; } if (!(obj instanceof Cat)) { return false; } if (this == obj) { return true; } return (this.color.equals(((Cat) obj).color)); } public static void main(String[] args) { Cat cat1 = new Cat("白色"); Cat cat2 = new Cat("黑色"); System.out.println(cat1.equals(cat2)); //false,因为重写了equals方法,且他们的颜色不一样,所以返回false。 HashMap<Cat, String> maps = new HashMap<>(); maps.put(cat1, "白色"); maps.put(cat2, "黑色"); System.out.println(maps.get(new Cat("白色"))); //null,因为没有重写hashcode方法,所以在查找的时候计算的hashcode值不一样,无法找到,所以返回null。 } }
对于Java中所有类的超级父类java.lang.Object而言,其hashCode()的默认实现是:对于不同的对象就返回不同的整型值。上述示例代码中,Cat类没有重写Object的hashCode()方法。所以,这条代码System.out.println(maps.get(new Cat("白色")));创建的Cat类和cat1的hasncode值不一样,所以无法找到。
- 重写
hashCode
后
import java.util.HashMap; public class Cat { private String color; public Cat(String color) { this.color = color; } public boolean equals(Object obj) { if (obj == null) { return false; } if (!(obj instanceof Cat)) { return false; } if (this == obj) { return true; } return (this.color.equals(((Cat) obj).color)); } @Override public int hashCode() { return this.color.hashCode(); } public static void main(String[] args) { Cat cat1 = new Cat("白色"); Cat cat2 = new Cat("黑色"); System.out.println(cat1.equals(cat2)); // false HashMap<Cat, String> maps = new HashMap<>(); maps.put(cat1, "白色"); maps.put(cat2, "黑色"); System.out.println(maps.get(new Cat("白色"))); // 白色 } }
摘自: 简书.
参考: 1. ==和equals的区别
- 未重写
网友评论