Integer類型的比較是面試中常問的一個東西,, 涉及基本數據類型,引用數據類型的裝箱拆箱,類加載機制等。首先看下面兩段代碼的執行結果
public static void IntegerDemo1() { Integer i1 = 100; Integer i2 = 100; System.out.println(i1.hashCode()); System.out.println(i2.hashCode()); System.out.println("比較結果:" + (i1 == i2)); System.out.println("比較結果:" + i1.equals(i2)); System.out.println("比較結果:" + i1.compareTo(i2)); }
100 100 比較結果:true 比較結果:true 比較結果:0
public static void IntegerDemo1() { Integer i1 = 200; Integer i2 = 200; System.out.println(i1.hashCode()); System.out.println(i2.hashCode()); System.out.println("比較結果:" + (i1 == i2)); System.out.println("比較結果:" + i1.equals(i2)); System.out.println("比較結果:" + i1.compareTo(i2)); }
200 200 比較結果:false 比較結果:true 比較結果:0
為什么Integer的值是100和200時會出現不同的結果呢?
首先要知道Integer i1 = 100做了什么? 在做這樣的操作時,實際就是基本數據類型與引用類型之間的拆箱和裝箱操作,Integer i1 = 100是一個裝箱操作,本質就是Integer i1 = Integer.valueOf(100),源碼如下:
public static Integer valueOf(int i) { if (i >= IntegerCache.low && i <= IntegerCache.high) return IntegerCache.cache[i + (-IntegerCache.low)]; return new Integer(i); }
在valueOf方法,,對賦的值進行一個判斷操作,如果值在-128~127之間,就會在內部類IntegerCache的cache[]數組中獲取一個Integer對象,如果不是就new一個新的Integer對象.
那么cache[]中又是什么呢?
cache = new Integer[(high - low) + 1]; int j = low; for(int k = 0; k < cache.length; k++) cache[k] = new Integer(j++);
從IntegerCache中的一段源碼中可以發現cache[]中循環放入了值在-128~127之間的Integer對象,根據內部類加載機制,當類第一次調用時會初始化這個數組,並且在JVM中只初始化一次,到這里我們就明白了為什么賦值在-128~127之間的比較時能夠相等,因為==比較的是內存地址,示例代碼中的變量i1和i2在這個范圍內都引用了從cache取出的同一個對象,對象內存地址一樣,所以是相等的,在超出這個范圍之后,每次創建會new一個新的Integer對象,引用的是不同的對象,所以不相等.
那為什么equals方法一直相等呢?
public boolean equals(Object obj) { if (obj instanceof Integer) { return value == ((Integer)obj).intValue(); } return false; }
可以看到Integer對equals方法進行重寫,從比較兩個對象的內存地址變成了比較兩個Integer對象的的值,這與String類相似,同時重寫的還有hashCode()方法,hashcode返回了對象的值.
那為什么要設計IntegerCache類來緩存-128~127的對象呢?
節省內存消耗,提高程序性能,Integer是一個經常使用到的類,並且一般創建的對象值范圍都在-128~127之間,並且創建這樣相似值的對象並沒有太大意義,所以使用IntegerCache類,與此類似的ByteCache、ShortCache等.
那Integer比較用什么方法呢?
推薦compareTo方法,其次equals方法