一、傳統認知
運算 |
基本數據類型比較的對象 |
引用數據類型比較的對象 |
== |
值 |
堆內存空間 |
equals |
值 |
默認堆內存空間,覆寫的方法除外 |
二、通過程序找問題
import com.leon.java.reflect.Person;
class Dog{
private String name ;
Dog(){}
Dog(String name){
this.name = name;
}
}
public class EqualsDemo<T> {
void test(T t1,T t2){
System.out.println("t1是否==t2:" + (t1 == t2));
System.out.println("t1是否equals t2:" + (t1.equals(t2)));
}
public static void main(String[] args) {
// == 比較 基本類型
System.out.println("\n--------比較基本類型-------");
System.out.println("\n1.比較Byte");
new EqualsDemo<Byte>().test((byte)123,(byte)123);
System.out.println("\n2.比較Short");
new EqualsDemo<Short>().test((short)123,(short)123);
System.out.println("\n3.比較Integer");
new EqualsDemo<Integer>().test(1,1);
System.out.println("\n4.比較Long");
new EqualsDemo<Long>().test(123L,123L);
System.out.println("\n5.比較Float");
new EqualsDemo<Float>().test(1.4f,1.4f);
System.out.println("\n6.比較Double");
new EqualsDemo<Double>().test(1.433333,1.433333);
System.out.println("\n7.比較char");
new EqualsDemo<Character>().test('a','a');
System.out.println("\n8.比較Boolean");
new EqualsDemo<Boolean>().test(true,true);
//發現的問題1:浮點型兩個“相同的數” == 比較結果不同。解決方法:浮點型數據比較是否相等時,轉化成包裝類型,使用equals進行比較。
//比較引用類型
System.out.println("\n--------比較引用類型-------");
Dog d1 = new Dog("旺旺");
Dog d2 = new Dog("旺旺");
System.out.println("\n比較自定義的Dog類");
new EqualsDemo<Dog>().test(d1,d2);
System.out.println("\n比較String");
new EqualsDemo<String>().test("aaa","aaa");
//發現問題:String是引用類型,==比較引用類型時,比較的應該是地址纔對。爲什麼在這裏兩個String對象的比較結果是true。
}
}
JDK1.8下輸出結果爲:
--------比較基本類型-------
1.比較Byte
t1是否==t2:true
t1是否equals t2:true
2.比較Short
t1是否==t2:true
t1是否equals t2:true
3.比較Integer
t1是否==t2:true
t1是否equals t2:true
4.比較Long
t1是否==t2:true
t1是否equals t2:true
5.比較Float
t1是否==t2:false
t1是否equals t2:true
6.比較Double
t1是否==t2:false
t1是否equals t2:true
7.比較char
t1是否==t2:true
t1是否equals t2:true
8.比較Boolean
t1是否==t2:true
t1是否equals t2:true
--------比較引用類型-------
比較自定義的Dog類
t1是否==t2:false
t1是否equals t2:false
比較String
t1是否==t2:true
t1是否equals t2:true
這裏我們不難發現兩個問題:
問題1:浮點型兩個“相同的數” == 比較結果爲什麼不同?
問題2:String是引用類型,==比較引用類型時,比較的應該是地址纔對。爲什麼在這裏兩個String對象的比較結果是true?
三、解決問題
1.浮點型數據判斷是否相等
答:這個問題的由來比較古老,是浮點型這種數據類型的設計導致了這種情況。當然,JDK的開發人員也知道這個問題,於是他們提供了這樣的解決方法:
意思是:只要參數傳入的對象是Double類型,且當前對象和傳入對象的“doubleToLongBits()”相同即認定爲兩者相等。
我們來看doubleToLongBits(double value)方法。
第一行就調用了另一個方法:
doubleToRawLongBits();
java.lang.Double.doubleToRawLongBits() 方法返回根據IEEE754浮點“雙精度格式”位佈局,不是非數字(NaN)值,返回指定浮點值的表示。它包括以下要點:
- 如果參數爲正無窮大,其結果是 0x7ff0000000000000L.
- 如果參數爲負無窮大,其結果是 0xfff0000000000000L.
- 如果參數爲NaN,那麼結果是長整型表示實際NaN值。doubleToLongBits方法不同,doubleToRawLongBits不垮所有的位模式NaN編碼爲一個單一的“規範”NaN值。
簡單理解:
上面的內容有點多不想看,可以簡單理解爲:Double的equals()方法是通過將double型轉換成long型變量,來進行數值比較的。
2.String是引用類型,==比較引用類型時,比較的應該是堆內存纔對。爲什麼在這裏兩個String對象的比較結果是true?
答:java代碼實際的執行引擎是jvm,jvm爲String型變量提供了緩存機制,只要內容相同的String實例,不會重新創建對象,而是重用已經存在的對象。