java andequal_Java equals 和 == 完全解析
今天朋友突然問到一個問題:兩個對象使用x.equals(y)判斷結果為true時,兩個對象的hashCode可以不同嗎?
在Java編程中,判斷兩個對象是否相等常常使用equals()或是==,但是其中的區別和原理可能很多人并不完全清楚。今天就借著上面這個問題來看看equals()和==的區別和原理。
1. 數據類型與==的含義
Java中的數據類型分為基本數據類型和引用數據類型:基本類型:編程語言中內置的最小粒度的數據類型。它包括四大類八種類型4種整數類型:byte、short、int、long
2種浮點數類型:float、double
1種字符類型:char
1種布爾類型:boolean
引用類型:引用也叫句柄,引用類型,是編程語言中定義的在句柄中存放著實際內容所在地址的地址值的一種數據形式類
接口
數組
對于基本類型來說,== 比較的是它們的值
對于引用類型來說,== 比較的是它們在內存中存放的地址(堆內存地址)
例:
public void test(){
int num1 = 100;
int num2 = 100;
String str1 = "James";
String str2 = "James";
String str3 = new String("James");
String str4 = new String("James");
System.out.println("num1 == num2 : " + (num1 == num2));
System.out.println("str1 address : " + System.identityHashCode(str1) + ";\nstr2 address : " + System.identityHashCode(str1) + ";\nstr1 == str2 : " + (str1 == str2));
System.out.println("str3 address : " + System.identityHashCode(str3) + ";\nstr4 address : " + System.identityHashCode(str4) + ";\nstr3 == str4 : " + (str3 == str4));
}
運行上面的代碼,可以得到以下結果:
num1 == num2 : true
str1 address : 1174290147;
str2 address : 1174290147;
str1 == str2 : true
str3 address : 1289696681;
str4 address : 1285044316;
str3 == str4 : false
可以看到str1和str2的內存地址都是1174290147,所以使用==判斷為true,但是str3和str4的地址是不同的,所以判斷為false。
2. equals() 方法解析
在Java語言中,所有類都是繼承于Object這個超類的,在這個類中也有一個equals()方法,那么我們先來看一下這個方法。
public boolean equals(Object obj) {
return (this == obj);
}
可以看得出,這個方法很簡單,就是比較對象的內存地址的。所以在對象沒有重寫這個方法時,默認使用此方法,即比較對象的內存地址值。但是類似于String、Integer等類均已重寫了equals()。下面以String為例。
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String)anObject;
int n = length();
if (n == anotherString.length()) {
int i = 0;
while (n-- != 0) {
if (charAt(i) != anotherString.charAt(i))
return false;
i++;
}
return true;
}
}
return false;
}
很明顯,String的equals()方法僅僅是對比它的 數據值,而不是對象的 內存地址 。
以 String 為例測試一下。
public void test() {
String str1 = "James";
String str2 = "James";
String str3 = new String("James");
String str4 = new String("James");
System.out.println("str1 address : " + System.identityHashCode(str1) + ";\nstr2 address : " + System.identityHashCode(str1) + ";\nstr1.equals(str2) : " + str1.equals(str2));
System.out.println("str3 address : " + System.identityHashCode(str3) + ";\nstr4 address : " + System.identityHashCode(str4) + ";\nstr3.equals(str4) : " + str3.equals(str4));
}
結果為:
str1 address : 1174290147;
str2 address : 1174290147;
str1.equals(str2) : true
str3 address : 1289696681;
str4 address : 1285044316;
str3.equals(str4) : true
可以發現不管對象的內存地址是否相同并不影響其結果,所以String類型比較的是 數據值, 而不是 內存地址值。
所以總結一下equals() 和 == 的區別:==基本類型:對比它們的值是否相等
引用類型:對比它們的內存地址是否相等equals()基本類型:使用==進行比較
引用類型:默認情況下,對比它們的地址是否相等;如果equals()方法被重寫,則根據重寫的要求來比較。
3. equals() 與 hashCode()
在詳細的了解了==和equals()的作用和區別后,現在來研究一下之前的那個問題:兩個對象使用x.equals(y)判斷結果為true時,兩個對象的hashCode可以不同嗎?
首先我們需要知道hashCode到底是什么?還是從Object這個超類來看一下。
public int hashCode() {
return identityHashCode(this); // 此處返回對象的內存地址值
}
代碼也很簡單,看來默認情況下,hashCode就等于對象的 內存地址值(注:System.identityHashCode(Object obj)方法用于獲取對象的內存地址,之前的樣例代碼中有使用)。和equals()方法一樣重寫之后,hashCode()方法方法也是可以被重寫的,而且兩者一般情況下都是成對出現。
簡單測試一下String類型重寫hashCode()方法之后有什么變化。
public void test() {
String str1 = "James";
System.out.println("str1 address : " + System.identityHashCode(str1) + "\nstr1 hashCode : " + str1.hashCode());
}
結果為:
str1 address : 1174290147
str1 hashCode : 71338276
很明顯,hashCode 已經不是內存地址了。
那么總結一下:equals():默認情況下比較的是對象的 內存地址值,被重寫后按照重寫要求進行比較,一般是比較對象的 數據值
hashCode(): 默認情況下為對象的 內存地址值,被重寫后按照重寫要求生成新的值。
到此對于剛開始提出的問題應該很好解決了。對于這兩個對象,只要我們重寫equals()方法,就可以比較對象的 數據值,而不重寫hashCode()方法,此時兩個對象的 hashCode 就默認為內存地址值了,只要將兩個對象指向不同的地址即可。
驗證環節,先創建一個類:
public class CustomBean {
private String name;
private int age;
public CustomBean(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
CustomBean that = (CustomBean) o;
return age == that.age &&
Objects.equals(name, that.name);
}
// @Override
// public int hashCode() {
// return Objects.hash(name, age);
// }
}
創建測試方法:
@Test
public void test() {
CustomBean x = new CustomBean("James", 18);
CustomBean y = new CustomBean("James", 18);
System.out.println("x.hashCode: " + x.hashCode());
System.out.println("x address : " + System.identityHashCode(x));
System.out.println("y.hashCode: " + y.hashCode());
System.out.println("x address : " + System.identityHashCode(y));
System.out.println("x and y is equals : " + x.equals(y));
}
運行結果為:
x.hashCode: 1174290147
x address : 1174290147
y.hashCode: 1289696681
x address : 1289696681
x and y is equals : true
很明顯,這就是問題中所描述的那種情況:兩個對象使用x.equals(y)判斷結果為true時,兩個對象的hashCode不相同。
4. 總結
至此,==和equals()的區別及作用,equals()和hashCode的關系及使用已經了解清楚了。下面再總結一下:
對于equals() 和 == 的區別:==基本類型:對比它們的值是否相等
引用類型:對比它們的內存地址是否相等
equals()基本類型:使用==進行比較
引用類型:默認情況下,對比它們的地址是否相等;如果equals()方法被重寫,則根據重寫的要求來比較
對于equals()和hashCode()的關系:
根據Object超類中的文檔說明,equals()和hashCode()兩個方法應該 同進同退。上面的例子只是舉例說明存在那種情況,但那并不是一個很好的應用。所以一定要記住equals()和hashCode()兩個方法應該 同進同退。
所以一定要記住equals()和hashCode()兩個方法應該 同進同退。
所以一定要記住equals()和hashCode()兩個方法應該 同進同退。
重要的事情說三遍。
總結
以上是生活随笔為你收集整理的java andequal_Java equals 和 == 完全解析的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 春泥计算机科技怎么样,2021人工智能就
- 下一篇: matlab用辛普森公式求积分_数值计算