您好,登錄后才能下訂單哦!
這篇文章主要講解了“java Integer等號判斷怎么使用”,文中的講解內容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“java Integer等號判斷怎么使用”吧!
先來看一道常見的面試題,對照上面的結論,看看能夠答對幾項。下面代碼中打印結果為true的有幾項?
@Test public void test2() { Integer i1 = 64; int i2 = 64; Integer i3 = Integer.valueOf(64); Integer i4 = new Integer(64); Integer i5 = 256; Integer i6 = Integer.valueOf(256); System.out.println("A:" + (i1 == i2)); System.out.println("B:" + (i1 == i3)); System.out.println("C:" + (i3 == i4)); System.out.println("D:" + (i2 == i4)); System.out.println("E:" + (i3.equals(i4))); System.out.println("F:" + (i5 == i6)); }
執行上面的程序,打印結果為:
A:true B:true C:false D:true E:true F:false
只有C和F項打印為false。你是否疑惑為什么i1等于i2,i1等于i3,i2等于i4,都為true,那么根據等號的傳遞性,i3應該等于i4啊?
為什么i1和i3相等,但i5和i6卻不相等呢?
先保留疑問。下面,我們從int及Integer在JVM中的存儲結構來進行分析。掌握了底層存儲結構,你會發現無論題面如何變化,都萬變不離其宗。
在徹底弄清楚上問題之前,我們先來了解一下基礎類型變量、引用類型變量在JVM中的存儲。
通常變量分為局部變量和全局(成員)變量。局部變量是聲明在方法內的變量;全局變量是聲明在類中的成員變量。
基礎類型的變量和值在分配的時候是在一起的,都在方法區或棧內存或堆內存。而引用類型的變量和值不一定在一起。
當方法被調用時,Java虛擬機都同步創建一個棧幀,局部變量便存儲在其中。當方法結束虛擬機會釋放方法棧,其中聲明的變量隨著棧幀的銷毀而結束。因此,局部變量只能在方法中有效。
此過程中,基礎類型和引用類型的存儲有所區別:
(1)基本類型:變量和對應的值存放在JAVA虛擬機的棧中;
(2)引用類型:變量存儲在棧中,是一個內存地址,該地址值指向堆中的對象。
棧屬于線程私有的空間,局部變量的生命周期和作用域一般都很短,為了提高gc效率,所以沒必要放在堆里面。
全局變量存放在堆中,不會隨著方法結束而銷毀。同樣在類中聲明的變量也是分為基本類型和引用類型。
(1)基本類型:變量名和值存放在堆內存中。
(2)引用類型:變量是一個引用地址,該地址指向所引用的對象。此時,變量和對象都在堆中。
舉個簡單的例子,如下代碼:
public class Person { int age = 10; String name = "Tom"; }
對應的age和name的存儲結構如下圖:
結合上面的理論,我們通過一段代碼來分析一下各種類型所存儲的位置。
public class DemoTest { int y; // 變量和值均在堆上 public static void main(String[] args) { int x = 1; // 變量和值分配在棧上 String name = new String("cat"); // 數據在堆上,name變量的指針在棧上 String address = "北京"; // 數據在常量池,屬于堆空間,指針在棧上 Integer price = 4; // 包裝類型為引用類型,編譯時會自動裝拆箱,數據在堆上,指針在棧 } }
通過上面的實例,基本了解了不同類型的值的內存分配情況。下面我們重點討論局部變量。
下面先來看看在同一棧幀中,針對int類型的處理模式。
int a = 3; int b = 3;
上述代碼中a和b均為局部變量。假設編譯器先處理int a=3,此時會在棧中創建a的引用變量,然后查找棧中是否存在3這個值,如果沒有就將3存放進來,然后將a指向3。
接著處理int b=3,創建完b的引用變量后,同樣進行查找。因為在棧中已經有3這個值,便將b直接指向3。
此時,a與b同時指向3這個值,自然是相等的。
關于基礎類型與引用類型的底層比較,可稍微延伸一下:對于“==”操作符號,JVM會根據其兩邊相互比較的操作數的類型,在編譯時生成不同的指令:
(1)對于boolean,byte、short、int、long這種整形操作數會生成if_icmpne指令。該指令用于比較整形數值是否相等。
(2)如果操作數是對象的話,編譯器則會生成if_acmpne指令,與if_icmpne相比將i(int)改成了a(object reference)。
學習了上面的底層理論知識,我們基本上可以得出如下結論:(1)兩個int類型比較,直接使用雙等號即可;(2)int的包裝類Integer對象比較時,使用equals進行比較即可。
但上面的結果只能說E項目是正確的。其比較項還涉及到整形的裝箱拆箱操作、Integer的緩存。我們下面逐一分析。
先看Integer的初始化,根據Integer的內部實現,創建Integer有三種,分別是:
Integer a = new Integer(1); //創建新的類 Integer b = Integer.valueOf(2); Integer c = 3; //自動包裝,會調用valueOf方法
其中直接賦值底層會調用valueOf方法進行操作的,因此這兩種操作效果是一樣的。
因為通過new和valueOf創建的是完全兩個對象,那么針對題目中的C項,直接比較兩個對象的引用肯定是不相等的,因此結果為false。但B項為什么為true呢?后面我們會講到。
在題目中,我們發現A、D都為true,而且它們的比較格式都是基礎類型與包裝類型的對比。
針對這種形式的對比,包裝類型會進行自動拆箱,變成基礎類型(int)。很顯然,結果是相等的。
為什么i1和i3相等,但i5和i6卻不相等呢?對應題目中的B和G項。這里就涉及到Integer的緩存機制。
我們上面已經知道,Integer直接賦值和valueOf是等效的,那先看一下valueOf及相關的方法。
public static Integer valueOf(int i) { if (i >= IntegerCache.low && i <= IntegerCache.high) return IntegerCache.cache[i + (-IntegerCache.low)]; return new Integer(i); } 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 = sun.misc.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() {} }
valueOf方法判斷數字是否大于low(-128)并且小于high(127),如果滿足條件,則直接從IntegerCache中返回對應數字。
IntegerCache用于存儲一些常用的數,防止重復創建,在Integer類裝入內存時通過靜態代碼進行初始化。
所以只要是用valueOf或者Integer直接賦值的方式創建的對象,其值小于127且大于-128的,無論對其進行==比較還是equals 比較,都是true。
上面的源碼及原理也解釋了阿里Java開發手冊中所說明的原因。
對于不滿足-128到127范圍的數,無論通過什么方式創建,都會創建一個新的對象,只能通過equals進行比較。接下來我們再看看equals方法。
public boolean equals(Object obj) { if (obj instanceof Integer) { return value == ((Integer)obj).intValue(); } return false; }
equals實現比較簡單,先比較類型是否一致,如果不一致,直接返回false;否則,再比較兩者的值,相同則返回true。
感謝各位的閱讀,以上就是“java Integer等號判斷怎么使用”的內容了,經過本文的學習后,相信大家對java Integer等號判斷怎么使用這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。