發現做項目的過程中,在數值類型的比較上容易犯錯,特別是Integer和Integer的比較,Integer和int的比較。雖然這些都是些基礎語法,但稍不留意就容易犯錯,在實際開發過程中如果出現這類失誤,很容易失之毫厘謬以千里。在這里,總結下這些基礎知識點。
java雖然宣稱一切都是對象,但原始數據類型是例外。int是整形數字,是java的9個原始數據類型(Primitive Types)(boolean、byte、short、char、int、float、double、long、void)之一。Integer是int對應的包裝類,它有一個int類型的字段存儲數據,并且提供了基本操作,比如數學運算、int和字符串之間轉換等。在java 5中引入了自動裝箱和自動拆箱功能(boxing/unboxing),java可以根據上下文,自動進行轉換,極大地簡化了相關編程。javac自動把裝箱轉換為Integer.valueOf(),把拆箱替換為Integer.intValue()。
自動裝箱實際上算是一種語法糖。什么是語法糖?可以簡單理解為java平臺為我們自動進行了一些轉換,保證不同的寫法在運行時等價,他們發生在編譯階段,也就是生產的字節碼是一致的。(此句摘自極客時間專欄)
原始數據類型的變量,需要使用并發相關手段才能保證線程安全。如果有線程安全的計算需要,建議考慮使用類似AtomicInteger、AtomicLong這樣的線程安全類。
原始數據類型和java泛型并不能配合使用。因為java的泛型某種程度上可以算作偽泛型,它完全是一種編譯期的技巧,java編譯期會自動將類型轉換為對應的特定類型。這就決定了使用泛型,必須保證相應類型可以轉換為Object。
廢話不多說,直接來demo,這樣效果更直接。
public class Test {
public static void main(String[] args) {
Integer a1 = 6;
Integer a2 = 6;
int a11 = 6;
System.out.println(a1 == a2); //true
System.out.println(a1 == a11); //true
System.out.println("----------------");
Integer a3 = 128;
Integer a4 = 128;
int a33 = 128;
System.out.println(a3 == a4); //false
//Integer會自動拆箱為int,所以為true
System.out.println(a3 == a33); //true
System.out.println(a3.equals(a4)); //true
System.out.println("----------------");
Integer a5 = new Integer(6);
Integer a6 = new Integer(6);
System.out.println(a5 == a6); //false
System.out.println(a5.equals(a6)); //true
}
需要明確的一點是,包裝型(Integer)和基本型(int)比較會自動拆箱(jdk1.5以上)。
在這里很多人比較容易迷惑的是如下情況:
Integer a1 = 6;
Integer a2 = 6;
System.out.println(a1 == a2); //true
Integer a3 = 128;
Integer a4 = 128;
System.out.println(a3 == a4); //false
如果研究過jdk源碼,你就會發現Integer a3 = 128;在java編譯時會被翻譯成 Integer a3 = Integer.valueOf(128); 我們再來看看valueOf()的源碼就更清晰了。
public static Integer valueOf(int i) {
assert IntegerCache.high >= 127;
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
由以上源碼就會發現,對于-128到127之間的數,會進行緩存,Integer a1 = 6時,會將6進行緩存,下次再寫Integer a2 = 6;時,就會直接從緩存中取,也就不用new一個對象了,所以a1和a2比較時就為true。但a3和a4是超過范圍,會new一個對象,==是進行地址和值比較,是比較兩個對象在JVM中的地址,這時a3和a4雖然值相同但地址是不一樣的,所以比較就為false了。
通過上面的分析可知:
兩個都不是new出來的Integer,且數值在-128~127之間,用==比較時,基本值相等時為true,否則為false;
兩個都是new出來的Integer,為false
int和Integer比較,數值相同,用==比較時為true。(因為Integer會自動拆箱為int去比較)
所有包裝類對象之間值的比較,建議使用equals方法比較。
==判斷對象是否同一個。
Integer var = ?在緩存區間的賦值,會復用已有對象,因此這個區間內的Integer使用==進行判斷可通過,但是區間之外的所有數據,則會在堆上新產生,不會通過。
因此如果用== 來比較數值,很可能在小的測試數據中通過,而到了生產環境才出問題。
為了節省內容,對與下列包裝對象的兩個實例,當他們的基本值相同時,用==判斷會為true:
Boolean
Byte
Character, \u0000 - \u007f(7f是十進制的127)
Integer, -128 — 127
我們也可以看看其它包裝型的緩存情況:
Boolean:(全部緩存)
Byte:(全部緩存)
Character(緩存范圍'\u0000'到'\u007F')
Short(-128 — 127緩存)
Long(-128 — 127緩存)
Float(沒有緩存)
Doulbe(沒有緩存)
如果要比較兩個Integer對象的值(均為new的對象),可以通過.intValue()進行轉換后來比較,如下:
Integer a3 = 128;
Integer a4 = 128;
System.out.println(a3.intValue() == a4.intValue());
也可以使用equal()來進行比較,如下:
Integer a3 = 128;
Integer a4 = 128;
System.out.println(a3.equals(a4)); //true
本站文章版權歸原作者及原出處所有 。內容為作者個人觀點, 并不代表本站贊同其觀點和對其真實性負責,本站只提供參考并不構成任何投資及應用建議。本站是一個個人學習交流的平臺,網站上部分文章為轉載,并不用于任何商業目的,我們已經盡可能的對作者和來源進行了通告,但是能力有限或疏忽,造成漏登,請及時聯系我們,我們將根據著作權人的要求,立即更正或者刪除有關內容。本站擁有對此聲明的最終解釋權。