Java Integer對象的比較
Integer對象之間的比較要考慮到對象初始化的不同情況,初始化又涉及到對象包裝器類的自動裝箱特性 。
自動裝箱
Integer是一種對象包裝器類。對象包裝器類是不可變的,也就是說,一旦完成了構造,包裝在其中的值就不可以再被更改了。包裝器類有一種特性,自動裝箱。當需要一個Integer類型的對象時,可以對int類型的元素進行自動打包的操作。如果添加3到list中,實際調用的是下面的代碼。
1
2
3
|
ArrayList<Integer> list = new ArrayList(); list.add( 3 ); list.add(Integer.valueOf( 3 )); |
valueOf的源代碼如下
1
2
3
4
5
|
public static Integer valueOf( int i) { if (i >= IntegerCache.low && i <= IntegerCache.high) return IntegerCache.cache[i + (-IntegerCache.low)]; return new Integer(i); } |
其中IntegerCache定義如下
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
private static class IntegerCache { static final int low = - 128 ; static final int high; static final Integer cache[]; static { // high value may be configured by property int h = 127 ; String integerCacheHighPropValue = VM.getSavedProperty( "java.lang.Integer.IntegerCache.high" ); if (integerCacheHighPropValue != null ) { try { int i = parseInt(integerCacheHighPropValue); i = Math.max(i, 127 ); // Maximum array size is Integer.MAX_VALUE h = Math.min(i, Integer.MAX_VALUE - (-low) - 1 ); } catch ( NumberFormatException nfe) { // If the property cannot be parsed into an int, ignore it. } } high = h; cache = new Integer[(high - low) + 1 ]; int j = low; for ( int k = 0 ; k < cache.length; k++) cache[k] = new Integer(j++); // range [-128, 127] must be interned (JLS7 5.1.7) assert IntegerCache.high >= 127 ; } private IntegerCache() {} } |
JVM會維護一個Integer的數組,將值在某個范圍內(默認-128~127)的對象緩存起來,在這個范圍內的int會被包裝到固定的對象中,valueOf會返回緩存中的對象。如果不在這個范圍內,則會創建一個新的對象。注意,使用new創建的新對象是在堆中的,這一點會影響到Integer對象之間的比較結果。
自動拆箱
與自動裝箱對應的,存在自動拆箱操作。當將一個Integer對象賦值給一個int值時,編譯器就會插入對象拆箱指令。
1
2
|
int n = list.get(i); int n = list.get(i).intValue(); |
intvalue()源代碼就很簡單了,返回對象的value屬性
1
2
3
|
public int intValue() { return value; } |
Integer初始化
1.初始化Integer的時候,可以直接用一個int值賦值,實際上會自動裝箱。
1
2
|
Integer n1 = 3 ; Integer n1 = Integer.valueOf( 3 ); |
2.當然也可以使用new來創建Integer對象.
1
|
Integer n2 = new Integer( 3 ); |
Integer對象之間的比較
由于IntegerCache的存在,使用第一種方法初始化的對象,如果值的范圍在-128~127之間,則相同的值會被包裝的同一對象中。而用new產生的對象肯定不會在同一內存區域。
==運算符
如果使用==運算符進行比較的話,由于檢測的是對象是否指向同一個內存區域,由于初始化時的不確定性,比較的結果也可能不是我們想要的。如下所示:
1
2
3
4
5
6
7
8
9
10
11
|
Integer n1 = new Integer( 47 ); Integer n2 = new Integer( 47 ); Integer n3 = 47 ; Integer n4 = 47 ; Integer n5 = 200 ; Integer n6 = 200 ; System.out.println(n1 == n2); //false,兩個new的對象 System.out.println(n1 == n3); //false n1在堆中,n3指向IntegerCache緩存(方法區中) System.out.println(n3 == n4); //true 都指向緩存中同一個對象 System.out.println(n5 == n6); //false 超出緩存范圍,分別是兩個new出來的對象 |
equals
所以為了保持對象之間比較結果的一致性,同時我們進行比較的初衷應該也是比較它們之間的值,所以使用equals方法
1
2
3
4
5
6
|
public boolean equals(Object obj) { if (obj instanceof Integer) { return value == ((Integer)obj).intValue(); } return false ; } |
Integer類重寫了object的equals方法,調用時實際比較的是兩個對象的值,和對象存儲在哪里沒有關系。
Integer類型變量比較問題
今天在做實驗的時候,發現了一個比較奇怪的問題:兩個Integer型變量用==進行比較時,有時候能成功有時候不能成功。舉個例子:
代碼1
1
2
3
4
5
6
|
Integer l1 = 122 ; Integer l2 = 122 ; if (l1 == l2) System.out.println( "Right" ); else System.out.println( "Wrong" ); |
運行這段代碼時,程序會輸出:Right。對于另一個例子:
代碼2
1
2
3
4
5
6
|
Integer l1 = 233 ; Integer l2 = 233 ; if (l1 == l2) System.out.println( "Right" ); else System.out.println( "Wrong" ); |
運行這段代碼時,程序會輸出Wrong。但當對代碼2進行修改時:
代碼3
1
2
3
4
5
6
|
Integer l1 = 233 ; int l2 = 233 ; if (l1 == l2) System.out.println( "Right" ); else System.out.println( "Wrong" ); |
在運行這段代碼時,程序會輸出Right。如果換一種定義方式時:
代碼4
1
2
3
4
5
6
|
Integer l1 = 233 ; Integer l2 = new Integer( 233 ); if (l1 == l2) System.out.println( "Right" ); else System.out.println( "Wrong" ); |
運行這段代碼時,程序會輸出Wrong。
關于這種現象,查了下資料,總結如下
1.實際上Java中定義的Integer變量會通過Integer.valueOf()方法生成一個實例,即:
Integer l1 = 122 會被編譯成 Integer l1 = Integer.valueOf(122),而關于valueOf()方法的源碼:
1
2
3
4
5
6
|
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 l1 = 122時,會將122進行緩存,下次再寫Integer l2 = 122時,就會直接從緩存中取,就不會new了,相當于生成的為同一個對象,。所以代碼1的運行結果是Right。
而對于這個范圍之外的數值,valueOf()相會重新new一個對象,所以就不相等了,所以代碼2的裕興結果就是Wrong。
2.對于代碼3,Integer型變量與int型變量進行比較時,實質上是把Integer類型變量拆箱成int類型,然后進行比較,相等則返回true,否則返回false。此處的拆箱調用的是intValue()方法。所以代碼3的運行結果是Right。
3.對于代碼4,就比較好解釋了,因為new相當于重新定義了一個新的對象,即l1的引用實質是指向在堆中了,而l2實質是指向在常量池中了,所以兩者是不可能相等的,故輸出結果就是Wrong。
4.總之,要想比較兩個Intger型變量的值最好用Integer.intValue()方法生成int型后再比較。
5.Integer型變量與int型變量之間可以直接比較,此時自動進行拆箱操作。
以上為個人經驗,希望能給大家一個參考,也希望大家多多支持服務器之家。
原文鏈接:https://blog.csdn.net/bsbhenry/article/details/90743619