Java中Integer128的坑
今天在學(xué)習(xí)Java的時(shí)候遇到了下面幾個(gè)問題。
public static void main(String[] args) { Integer num1 = 127; Integer num2 = 127; Integer num3 = 128; Integer num4 = 128; int num5 = 127; int num6 = 128; System.out.println(num1 == num2); System.out.println(num3 == num4); System.out.println(num1 == num5); System.out.println(num6 == num3); }
我會認(rèn)為這個(gè)問題的輸出結(jié)果是true、true、true、true。但是在運(yùn)行的時(shí)候發(fā)現(xiàn),結(jié)果并不是想象中的那樣子。正確答案如下。
??一、Integer和int的聯(lián)系
Java 5 引入了自動裝箱(Autoboxing)和拆箱(Unboxing)機(jī)制,允許 int
類型和 Integer
類型之間進(jìn)行自動轉(zhuǎn)換。
- 自動裝箱:將
int
類型的值自動轉(zhuǎn)換為Integer
對象。 - 自動拆箱:將
Integer
對象自動轉(zhuǎn)換為int
類型的值。
1.1 Integer和int的區(qū)別
1. 類型不同
int
是基本數(shù)據(jù)類型,直接存儲整數(shù)值。Integer
是引用類型,存儲的是對象的引用,指向堆內(nèi)存中的Integer
對象。
2. 內(nèi)存使用
int
變量在棧內(nèi)存中直接存儲整數(shù)值,占用的內(nèi)存空間固定為 4 個(gè)字節(jié)。Integer
對象存儲在堆內(nèi)存中,除了存儲整數(shù)值外,還需要額外的內(nèi)存來存儲對象的元數(shù)據(jù),因此占用的內(nèi)存空間相對較大。
3. 空值處理
int
是基本數(shù)據(jù)類型,不能為null
。Integer
是引用類型,可以賦值為null
,這在某些需要表示 “無值” 的場景中非常有用。
1.2 Integer和int的相互轉(zhuǎn)換
在上一篇文章當(dāng)中說到了類和對象,Integer并不是八大基本數(shù)據(jù)類型中的一個(gè),Integer是一個(gè)類,類似于上一篇文章說到的學(xué)生類。
int轉(zhuǎn)換為Intege:裝箱
看下邊一行代碼。下邊這行代碼的執(zhí)行涉及到了裝箱操作。
Integer num1 = 127;
代碼真正在執(zhí)行的時(shí)候會變?yōu)橄路降臉幼?。這就是裝箱操作,就是把一個(gè)基本類型的int變量,包裝成一個(gè)引用類型的Integer變量。
Integer num1 = Integer.valueOf(127);
Integer轉(zhuǎn)換為int:拆箱
下方的代碼涉及到拆箱操作。
Integer num1 = 127; int num2 = num1;
代碼在執(zhí)行的時(shí)候會變?yōu)檫@個(gè)樣子。這就是拆箱操作。
Integer num1 = Ineger.valueOf(127); int num2 = num1.intValue();
??二、裝箱
想要知道最開始的問題,就要具體了解,裝箱到底是如何實(shí)現(xiàn)的,為什么對127裝箱作比較是true,對128裝箱后作比較是false,現(xiàn)在來跟進(jìn)裝箱的代碼。
跟進(jìn)到源碼當(dāng)中,我們發(fā)現(xiàn)這個(gè)方法對于我們傳入的數(shù)值還進(jìn)行了一次判斷,i要和IntegerCache的low和high作比較,如果在low和high之前,那么就返回一個(gè)值,否則的話就返回一個(gè)new出來的Integer對象。
IntegerCache.low
能夠看到,low其實(shí)是一個(gè)值,大小為-128
IntegerCache.high
同樣的,high也是一個(gè)值,只不過好像沒有初始值,這里我們先看做127。
對于一開始的問題,我們傳進(jìn)來的值是127。
Integer num1 = 127; Integer num2 = 127;
那么就會返回這個(gè)值。
return IntegerCache.cache[i + (-IntegerCache.low)];
IntegerCache.cache其實(shí)是一個(gè)Integer數(shù)組,用于存儲一些Integer類創(chuàng)建出的對象。
那么它可以有哪些對象呢?看如下代碼。
static { // high value may be configured by property int h = 127; String integerCacheHighPropValue = VM.getSavedProperty("java.lang.Integer.IntegerCache.high"); if (integerCacheHighPropValue != null) { try { h = Math.max(parseInt(integerCacheHighPropValue), 127); // Maximum array size is Integer.MAX_VALUE h = Math.min(h, Integer.MAX_VALUE - (-low) -1); } catch( NumberFormatException nfe) { // If the property cannot be parsed into an int, ignore it. } } high = h; // Load IntegerCache.archivedCache from archive, if possible CDS.initializeFromArchive(IntegerCache.class); int size = (high - low) + 1; // Use the archived cache if it exists and is large enough if (archivedCache == null || size > archivedCache.length) { Integer[] c = new Integer[size]; int j = low; for(int i = 0; i < c.length; i++) { c[i] = new Integer(j++); } archivedCache = c; } cache = archivedCache; // range [-128, 127] must be interned (JLS7 5.1.7) assert IntegerCache.high >= 127; }
這是一個(gè)靜態(tài)初始塊,現(xiàn)在不講太多,只是Integer類加載的時(shí)候會執(zhí)行里邊的代碼,在這里有對cache的初始化。我們只需要關(guān)注下邊的部分。
int size = (high - low) + 1; // Use the archived cache if it exists and is large enough if (archivedCache == null || size > archivedCache.length) { Integer[] c = new Integer[size]; int j = low; for(int i = 0; i < c.length; i++) { c[i] = new Integer(j++); } archivedCache = c; } cache = archivedCache;
size就是我們設(shè)置的(127 + 128) + 1,也就是256。cache初始化的過程如下。
- 根據(jù)low和high計(jì)算size
- 初始化一個(gè)size大小的Integer數(shù)組
- 對數(shù)組進(jìn)行賦值操作,也就是數(shù)組的0~255索引為存儲的是-128~127之間的數(shù)字(包括0)
現(xiàn)在我們已經(jīng)知道了,cache就是一個(gè)已經(jīng)初始化好的數(shù)組,里邊存儲了-128~127之間的Integer對象的引用。那么回到上訪的代碼。如果我們傳入的值在low~high之間,那么就會直接從這個(gè)cache中拿取已經(jīng)創(chuàng)建好的Integer變量。
return IntegerCache.cache[i + (-IntegerCache.low)];
現(xiàn)在有一點(diǎn)明白了,如果直接拿取的是已經(jīng)創(chuàng)建好的對象,是不是就意味著每次拿的時(shí)候獲取的都是同一個(gè)對象呢?就是這樣子。
Integer num3 = 128; Integer num4 = 128;
如果傳入的是128。那么就會通過new的方式來創(chuàng)建Integer對象,每次new出來的是一個(gè)全新的對象,所以通過new方式創(chuàng)建的對象在怎么比較也是false,因?yàn)橐妙愋蛯ο笾g用==操作,比較的是兩個(gè)對象的地址是否相同,也就是說num3和num4比較的是他們在內(nèi)存空間的地址是否是相同的,并非比較的他們的內(nèi)容是否都是128。
而num1和num2的比較其實(shí)也是比較地址,但是因?yàn)閚um1和num2指向的是同一個(gè)對象,所以就是true。
??三、拆箱
拆箱操作就很簡單了,調(diào)用intValue()方法返回包裝的整數(shù)。
public static void main(String[] args) { Integer num1 = 127; Integer num2 = 127; Integer num3 = 128; Integer num4 = 128; int num5 = 127; int num6 = 128; System.out.println(num1 == num2); // Integer.valueOf(127) == Integer.valueOf(127) System.out.println(num3 == num4); // Integer.valueOf(128) == Integer.valueOf(128) System.out.println(num1 == num5); // num1.intValue() == 127 System.out.println(num6 == num3); // num2.intValue() == 128 }
現(xiàn)在是否對這個(gè)問題了解的更多了一點(diǎn)呢。
到此這篇關(guān)于Java中Integer128的坑的文章就介紹到這了,更多相關(guān)Java Integer128內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Spring IOC和DI實(shí)現(xiàn)原理及實(shí)例解析
這篇文章主要介紹了Spring IOC和DI實(shí)現(xiàn)原理及實(shí)例解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-06-06對java for 循環(huán)執(zhí)行順序的詳解
今天小編就為大家分享一篇對java for 循環(huán)執(zhí)行順序的詳解,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-06-06springboot如何解決非controller類引用service的問題
這篇文章主要介紹了springboot如何解決非controller類引用service的問題,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-02-02java工具類實(shí)現(xiàn)文件壓縮zip以及解壓縮功能
這篇文章主要給大家介紹了關(guān)于java工具類實(shí)現(xiàn)文件壓縮zip以及解壓縮功能的相關(guān)資料,文中主要使用使用的是hutool工具類,Hutool是一個(gè)Java工具類庫,由國內(nèi)的程序員loolly開發(fā),目的是提供一些方便、快捷、實(shí)用的工具類和工具方法,需要的朋友可以參考下2024-02-02使用Jenkins自動化構(gòu)建工具進(jìn)行敏捷開發(fā)
這篇文章主要為大家介紹了使用Jenkins自動化構(gòu)建工具進(jìn)行敏捷開發(fā),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步早日升職加薪2022-04-04Java實(shí)現(xiàn)對視頻進(jìn)行截圖的方法【附ffmpeg下載】
這篇文章主要介紹了Java實(shí)現(xiàn)對視頻進(jìn)行截圖的方法,結(jié)合實(shí)例形式分析了Java使用ffmpeg針對視頻進(jìn)行截圖的相關(guān)操作技巧,并附帶ffmpeg.exe文件供讀者下載使用,需要的朋友可以參考下2018-01-01