基礎很重要,基礎很重要,基礎很重要。重要的事情說三遍,。程序員
今天聊一聊Java的數據比較,這個範圍比較大,基礎類型的比較、引用類型的比較。c#
前提:緩存
一、Java和c#都提供自動裝箱和自動拆箱操做,何爲自動裝箱,簡單點說就是將值類型轉換成爲引用類型,自動拆箱就是將引用類型轉換成爲值類型。而且咱們還常常被教導,要避免自動的裝箱和拆箱操做,由於這個會影響性能。ide
二、比較經常使用的運算符是==,equals。性能
下面分幾類來講明數據的比較,學習
引用類型之間的比較:Integer與Integer之間的比較、Boolean與Boolean之間的比較、Integer與Boolean之間的比較編碼
值類型之間的比較:int與int之間的比較、int與bool之間的比較spa
值類型與引用類型之間的比較:Integer與int之間的比較、Boolean與bool之間的比較設計
開工code
引用類型之間的比較--Integer與Integer之間的比較
簡單說明一下,Integer是引用類型,表明的是整形數字
上代碼
1 public static void main(String[] args) throws Exception { 2 Integer integer = new Integer(0); 3 Integer mInteger = Integer.valueOf(0); 4 Integer sInteger = 0; 5 6 System.out.println(integer == mInteger);//false 7 System.out.println(integer == sInteger);//false 8 System.out.println(mInteger == sInteger);//true 9 10 System.out.println(memoryAddress(integer)); 11 System.out.println(memoryAddress(mInteger)); 12 System.out.println(memoryAddress(sInteger)); 13 14 } 15 16 private static int memoryAddress(Object object) { 17 // 內存地址會有所不一樣 18 return System.identityHashCode(object); 19 }
執行結果:
分析:
一、執行結果和咱們預想的不太同樣,引用類型是在堆上存放的,每一個引用的地址應該都不相同。可是mInteger == sInteger 執行結果爲true,而且mInteger ,sInteger的內存地址是相同的。
二、要分析這個緣由,咱們須要瞭解Java設計者爲了性能而進行的一些努力,查看Java源代碼,能夠看到Integer的valueof方法裏面包含了一個緩存:其中IntegerCache.low =-127,IntegerCache.high=128
1 @HotSpotIntrinsicCandidate 2 public static Integer valueOf(int i) { 3 if (i >= IntegerCache.low && i <= IntegerCache.high) 4 return IntegerCache.cache[i + (-IntegerCache.low)]; 5 return new Integer(i); 6 }
對於使用Integer.valueof()方法,若是數值是-127至128,那麼會使用緩存對象,不然會new一個對象。
三、Integer sInteger = 0; 發生了什麼呢?自動裝箱,等價於Integer sInteger=Integer.valueOf(0)。經過這個,咱們就能夠得出比較等於true的緣由了,都是從緩存中讀取的對象,難怪內存地址會一致。
引用類型比較--Integer與Integer引用類型比較 使用equals
上代碼:
1 public static void main(String[] args) throws Exception { 2 Integer integer = new Integer(0); 3 Integer mInteger = Integer.valueOf(0); 4 Integer sInteger = 0; 5 6 System.out.println(integer == mInteger);// false 7 System.out.println(integer == sInteger);// false 8 System.out.println(mInteger == sInteger);// true 9 10 System.out.println(memoryAddress(integer)); 11 System.out.println(memoryAddress(mInteger)); 12 System.out.println(memoryAddress(sInteger)); 13 14 System.out.println(integer.equals(mInteger));//true 15 System.out.println(integer.equals(sInteger));//true 16 System.out.println(mInteger.equals(sInteger));//true 17 18 } 19 20 private static int memoryAddress(Object object) { 21 // 內存地址會有所不一樣 22 return System.identityHashCode(object); 23 }
分析:使用equals比較,只要數值相同,那麼比較結果就是相同。查看Java源代碼:
1 public boolean equals(Object obj) { 2 if (obj instanceof Integer) { 3 return value == ((Integer)obj).intValue(); 4 } 5 return false; 6 }
能夠看到Integer的equals比較,其實比較的就是數值。
值類型之間的比較:int與int
上代碼
1 int m=0; 2 int i=0; 3 int s=0; 4 System.out.println(m==i);//true 5 //值類型是沒有equals方法 6 //System.out.println(m.equals(i));
分析:對於int 的比較,無需多言,原本就是數值比較。
Integer與int的比較:
1 Integer integer = new Integer(0); 2 Integer mInteger = Integer.valueOf(0); 3 Integer sInteger = 0;// 等價於Integer。valueof 4 int i = 0; 5 System.out.println(integer == i);//true 6 System.out.println(mInteger == i);//true 7 System.out.println(sInteger == i);//true 8 System.out.println(integer.equals(i));//true 9 System.out.println(mInteger.equals(i));//true 10 System.out.println(sInteger.equals(i));//true
分析:
一、Integer類型與int類型經過==比較,Integer會自動拆箱,轉換成int數值進行比較
二、equals方法更是讀取對應的int數值進行比較。
所以引用類型與值類型之間的比較,使用equals與==均可以。
簡單總結:
一、引用類型之間的比較,因爲存在-127至128之間的緩存對象,所以使用== 進行比較存在風險。優先使用equals進行比較
二、引用類型與值類型進行比較,因爲會自動拆箱,所以使用==和equals均可以正確獲得結果
三、建議在實際編碼過程當中,對數值的比較使用equals
深刻總結:
不單單Integer,其餘的基本類型也都存在緩存,下面給出一個簡單圖表進行說明
基本類型 | 裝箱類型 | 取值範圍 | 是否緩存 | 緩存範圍 |
byte | Byte | -128~127 | 是 | -128~127 |
short | Short | -2^15 ~ (2^15 - 1) | 是 | -128~127 |
int | Integer | -2^31 ~ (2^31 - 1) | 是 | -128~127 |
|
Long | -2^63 ~ (2^63 - 1) | 是 | -128~127 |
float | Float | -- | 否 | |
double | Double |
|
否 | |
boolean | Boolean | true、false | 是 | true、false |
char | Character | \u0000 ~ \uffff | 是 | \u0000 ~ \uffff |
Java博大精深,要想深刻,基礎必需要好,才能避免bug。
咱們程序員的職責就是少寫bug,這纔是咱們一直學習的動力。