欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

關(guān)于Java中你所不知道的Integer詳解

 更新時(shí)間:2017年12月03日 11:04:16   作者:光變  
這篇文章主要給大家介紹了關(guān)于Java中你所不知道的一些關(guān)于Integer的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧。

前言

本文主要給大家介紹了關(guān)于Java中Integer的相關(guān)內(nèi)容,分享出來(lái)供大家參考學(xué)習(xí),下面話不多說(shuō)了,來(lái)一起看看詳細(xì)的介紹吧。

實(shí)參形參

前些天看到朋友圈分享了一片文章《Java函數(shù)的傳參機(jī)制——你真的了解嗎?》

有些觸發(fā),之前也研究過(guò)Java的Integer,所以寫下本文,希望對(duì)你有所幫助。

交換

首先來(lái)看一個(gè)示例。

請(qǐng)用Java完成swap函數(shù),交換兩個(gè)整數(shù)類型的值。

public static void test() throws Exception {
 Integer a = 1, b = 2;
 swap(a, b);
 System.out.println("a=" + a + ", b=" + b);
}

static void swap(Integer a, Integer b){
 // 需要實(shí)現(xiàn)的部分
}

第一次

如果你不了解Java對(duì)象在內(nèi)存中的分配方式,以及方法傳遞參數(shù)的形式,你有可能會(huì)寫出以下代碼。

public static void swapOne(Integer a, Integer b) throws Exception {
 Integer aTempValue = a;
 a = b;
 b = aTempValue;
}

運(yùn)行的結(jié)果顯示a和b兩個(gè)值并沒(méi)有交換。

那么讓我們來(lái)看一下上述程序運(yùn)行時(shí),Java對(duì)象在內(nèi)存中的分配方式:


對(duì)象地址分配

由此可以看到,在兩個(gè)方法的局部變量表中分別持有的是對(duì)a、b兩個(gè)對(duì)象實(shí)際數(shù)據(jù)地址的引用。

上面實(shí)現(xiàn)的swap函數(shù),僅僅交換了swap函數(shù)里局部變量a和局部變量b的引用,并沒(méi)有交換JVM堆中的實(shí)際數(shù)據(jù)。

所以main函數(shù)中的a、b引用的數(shù)據(jù)沒(méi)有發(fā)生交換,所以main函數(shù)中局部變量的a、b并不會(huì)發(fā)生變化。

那么要交換main函數(shù)中的數(shù)據(jù)要如何操作呢?

第二次

根據(jù)上面的實(shí)踐,可以考慮交換a和b在JVM堆上的數(shù)據(jù)值?

簡(jiǎn)單了解一下Integer這個(gè)對(duì)象,它里面只有一個(gè)對(duì)象級(jí)int類型的value用以表示該對(duì)象的值。

所以我們使用反射來(lái)修改該值,代碼如下:

public static void swapTwo(Integer a1, Integer b1) throws Exception {
 Field valueField = Integer.class.getDeclaredField("value");
 valueField.setAccessible(true);
 int tempAValue = valueField.getInt(a1);
 valueField.setInt(a1, b1.intValue());
 valueField.setInt(b1, tempAValue);
}

運(yùn)行結(jié)果,符合預(yù)期。

驚喜

上面的程序運(yùn)行成后,如果我在聲明一個(gè)Integer c = 1, d = 2;會(huì)有什么結(jié)果

示例程序如下:

public static void swapTwo(Integer a1, Integer b1) throws Exception {
 Field valueField = Integer.class.getDeclaredField("value");
 valueField.setAccessible(true);
 int tempAValue = valueField.getInt(a1);
 valueField.setInt(a1, b1.intValue());
 valueField.setInt(b1, tempAValue);
}

public static void testThree() throws Exception {
 Integer a = 1, b = 2;
 swapTwo(a, b);
 System.out.println("a=" + a + "; b=" + b);
 Integer c = 1, d = 2;
 System.out.println("c=" + c + "; d=" + d);
}

輸出的結(jié)果如下:

a=2; b=1
c=2; d=1

驚喜不驚喜!意外不意外!刺激不刺激!

深入

究竟發(fā)生了什么?讓我們來(lái)看一下反編譯后的代碼:

作者使用IDE工具,直接反編譯了這個(gè).class文件

public static void testThree() throws Exception {
 Integer a = Integer.valueOf(1);
 Integer b = Integer.valueOf(2);
 swapTwo(a, b);
 System.out.println("a=" + a + "; b=" + b);
 Integer c = Integer.valueOf(1);
 Integer d = Integer.valueOf(2);
 System.out.println("c=" + c + "; d=" + d);
}

在Java對(duì)原始類型int自動(dòng)裝箱到Integer類型的過(guò)程中使用了Integer.valueOf(int)這個(gè)方法了。

肯定是這個(gè)方法在內(nèi)部封裝了一些操作,使得我們修改了Integer.value后,產(chǎn)生了全局影響。

所有這涉及該部分的代碼一次性粘完(PS:不拖拉的作者是個(gè)好碼農(nóng)):

public class Integer{
 /**
 * @since 1.5
 */
 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() {}
 }
 
}

如上所示Integer內(nèi)部有一個(gè)私有靜態(tài)類IntegerCache,該類靜態(tài)初始化了一個(gè)包含了Integer.IntegerCache.lowjava.lang.Integer.IntegerCache.high的Integer數(shù)組。

其中java.lang.Integer.IntegerCache.high的取值范圍在[127~Integer.MAX_VALUE - (-low) -1]之間。

在該區(qū)間內(nèi)所有的Integer.valueOf(int)函數(shù)返回的對(duì)象,是根據(jù)int值計(jì)算的偏移量,從數(shù)組Integer.IntegerCache.cache中獲取,對(duì)象是同一個(gè),不會(huì)新建對(duì)象。

所以當(dāng)我們修改了Integer.valueOf(1)的value后,所有Integer.IntegerCache.cache[ 1 - IntegerCache.low ]的返回值都會(huì)變更。

我相信你們的智商應(yīng)該理解了,如果不理解請(qǐng)?jiān)谠u(píng)論區(qū)call 10086。

好了,那么不在[IntegerCache.low~IntegerCache.high)的部分呢?

很顯然,它們是幸運(yùn)的,沒(méi)有被IntegerCache緩存到,法外之民,每次它們的到來(lái),都會(huì)new一邊,在JVM上分配一塊土(內(nèi))地(存)。

遐想

如果我把轉(zhuǎn)換的參數(shù)換成類型換成int呢?

public static void testOne() throws Exception {
 int a = 1, b = 2;
 swapOne(a, b);
 System.out.println("a=" + a + ", b=" + b);
}

static void swapOne(int a, int b){
 // 需要實(shí)現(xiàn)的部分
}

以作者目前的功力,無(wú)解。高手可以公眾號(hào)留言,萬(wàn)分感謝!

至此swap部分已經(jīng)講完了。

1 + 1

首先讓我們來(lái)看一下代碼:

public static void testOne() {
 int one = 1;
 int two = one + one;
 System.out.printf("Two=%d", two);
}

請(qǐng)問(wèn)輸出是什么?

如果你肯定的說(shuō)是2,那么你上面是白學(xué)了,請(qǐng)直接撥打95169。

我可以肯定的告訴你,它可以是[Integer.MIN_VALUE~Integer.MAX_VALUE]區(qū)間的任意一個(gè)值。

驚喜不驚喜!意外不意外!刺激不刺激!

讓我們?cè)贁](捋)一(一)串(遍)燒(代)烤(碼)。

作者使用IDE工具,直接反編譯了這個(gè).class文件

public static void testOne() {
 int one = 1;
 int two = one + one;
 System.out.printf("Two=%d", two);
}

這里的變量two竟然沒(méi)有調(diào)用Integer.valueOf(int) ,跟想象的不太一樣,我懷疑這是IDE的鍋。

所以果斷查看編譯后的字節(jié)碼。以下為摘錄的部分字節(jié)碼:

LDC "Two=%d"
ICONST_1
ANEWARRAY java/lang/Object
DUP
ICONST_0
ILOAD 2
INVOKESTATIC java/lang/Integer.valueOf (I)Ljava/lang/Integer;
AASTORE
INVOKEVIRTUAL java/io/PrintStream.printf (Ljava/lang/String;[Ljava/lang/Object;)Ljava/io/PrintStream;
POP

可以看出確實(shí)是IDE的鍋,這里不僅調(diào)用了一次Integer.valueOf(int) ,而且還創(chuàng)建一個(gè)Object的數(shù)組。

完整的Java代碼應(yīng)該是如下所示:

public static void testOne() {
 int one = 1;
 int two = one + one;
 Object[] params = { Integer.valueOf(two) };
 System.out.printf("Two=%d", params);
}

所以只要在方法調(diào)用前修改Integer.IntegerCache.cache[2+128]的值就可以了,所以在類的靜態(tài)初始化部分加些代碼。

public class OnePlusOne {
 static {
 try {
 Class<?> cacheClazz = Class.forName("java.lang.Integer$IntegerCache");
 Field cacheField = cacheClazz.getDeclaredField("cache");
 cacheField.setAccessible(true);
 Integer[] cache = (Integer[]) cacheField.get(null);
 //這里修改為 1 + 1 = 3 
 cache[2 + 128] = new Integer(3);
 } catch (Exception e) {
 e.printStackTrace();
 }
 }

 public static void testOne() {
 int one = 1;
 int two = one + one;
 System.out.printf("Two=%d", two);
 }
}

two == 2 ?

在修改完Integer.IntegerCache.cache[2 + 128]的值后,變量two還等于2么?

public static void testTwo() {
 int one = 1;
 int two = one + one;
 System.out.println(two == 2);
 System.out.println(Integer.valueOf(two) == 2);
}

上述代碼輸出如下

true
false

因?yàn)閠wo == 2不涉及到Integer裝箱的轉(zhuǎn)換,還是原始類型的比較,所以原始類型的2永遠(yuǎn)等于2。

Integer.valueOf(two)==2的真實(shí)形式是Integer.valueOf(two).intValue == 2 ,即3==2,所以是false。

這里可以看到如果拿一個(gè)值為null的Integer變量和一個(gè)int變量用雙等號(hào)比較,會(huì)拋出NullPointException。

這里的方法如果換成System.out.println("Two=" + two)的形式會(huì)有怎樣的輸出?你可以嘗試一下。

后記

XCache

是否有Cache 最小值 最大值
Boolean 無(wú) -- --
Byte ByteCache -128 127(固定)
Short ShortCache -128 127(固定)
Character CharacterCache 0 127(固定)
Integer IntegerCache -128 java.lang.Integer.IntegerCache.high
Long LongCache -128 127(固定)
Float 無(wú) -- --
Double 無(wú) -- --

java.lang.Integer.IntegerCache.high

看了IntegerCache類獲取high的方法sun.misc.VM.getSavedProperty,可能大家會(huì)有以下疑問(wèn),我們不拖沓,采用一個(gè)問(wèn)題一解答的方式。

1. 這個(gè)值如何如何傳遞到JVM中?

和系統(tǒng)屬性一樣在JVM啟動(dòng)時(shí),通過(guò)設(shè)置-Djava.lang.Integer.IntegerCache.high=xxx傳遞進(jìn)來(lái)。

2. 這個(gè)方法和System.getProperty有什么區(qū)別?

為了將JVM系統(tǒng)所需要的參數(shù)和用戶使用的參數(shù)區(qū)別開,
java.lang.System.initializeSystemClass在啟動(dòng)時(shí),會(huì)將啟動(dòng)參數(shù)保存在兩個(gè)地方:

2.1 sun.misc.VM.savedProps中保存全部JVM接收的系統(tǒng)參數(shù)。

JVM會(huì)在啟動(dòng)時(shí),調(diào)用java.lang.System.initializeSystemClass方法,初始化該屬性。

同時(shí)也會(huì)調(diào)用sun.misc.VM.saveAndRemoveProperties方法,從java.lang.System.props中刪除以下屬性:

  • sun.nio.MaxDirectMemorySize
  • sun.nio.PageAlignDirectMemory
  • sun.lang.ClassLoader.allowArraySyntax
  • java.lang.Integer.IntegerCache.high
  • sun.zip.disableMemoryMapping
  • sun.java.launcher.diag

以上羅列的屬性都是JVM啟動(dòng)需要設(shè)置的系統(tǒng)參數(shù),所以為了安全考慮和隔離角度考慮,將其從用戶可訪問(wèn)的System.props分開。

2.2 java.lang.System.props中保存除了以下JVM啟動(dòng)需要的參數(shù)外的其他參數(shù)。

  • sun.nio.MaxDirectMemorySize
  • sun.nio.PageAlignDirectMemory
  • sun.lang.ClassLoader.allowArraySyntax
  • java.lang.Integer.IntegerCache.high
  • sun.zip.disableMemoryMapping
  • sun.java.launcher.diag

PS:作者使用的JDK 1.8.0_91

Java 9的IntegerCache

幻想一下,如果以上淘氣的玩法出現(xiàn)在第三方的依賴包中,絕對(duì)有一批程序員會(huì)瘋掉(請(qǐng)不要嘗試這么惡劣的玩法,后果很嚴(yán)重)。

慶幸的是Java 9對(duì)此進(jìn)行了限制??梢栽谙鄳?yīng)的module中編寫module-info.java文件,限制了使用反射來(lái)訪問(wèn)成員等,按照需要聲明后,代碼只能訪問(wèn)字段、方法和其他用反射能訪問(wèn)的信息,只有當(dāng)類在相同的模塊中,或者模塊打開了包用于反射方式訪問(wèn)。詳細(xì)內(nèi)容可參考一下文章:

在 Java 9 里對(duì) IntegerCache 進(jìn)行修改?

感謝Lydia和飛鳥的寶貴建議和辛苦校對(duì)。

最后跟大家分享一個(gè)java中Integer值比較不注意的問(wèn)題:

先來(lái)看一個(gè)代碼片段:

public static void main(String[] args) { 
Integer a1 = Integer.valueOf(60); //danielinbiti 
Integer b1 = 60; 
System.out.println("1:="+(a1 == b1)); 


Integer a2 = 60; 
Integer b2 = 60; 
System.out.println("2:="+(a2 == b2)); 


Integer a3 = new Integer(60); 
Integer b3 = 60; 
System.out.println("3:="+(a3 == b3)); 

Integer a4 = 129; 
Integer b4 = 129; 
System.out.println("4:="+(a4 == b4)); 
} 

這段代碼的比較結(jié)果,如果沒(méi)有執(zhí)行不知道各位心中的答案都是什么。

要知道這個(gè)答案,就涉及到Java緩沖區(qū)和堆的問(wèn)題。

java中Integer類型對(duì)于-128-127之間的數(shù)是緩沖區(qū)取的,所以用等號(hào)比較是一致的。但對(duì)于不在這區(qū)間的數(shù)字是在堆中new出來(lái)的。所以地址空間不一樣,也就不相等。

Integer b3=60 ,這是一個(gè)裝箱過(guò)程也就是Integer b3=Integer.valueOf(60)

所以,以后碰到Integer比較值是否相等需要用intValue()

對(duì)于Double沒(méi)有緩沖區(qū)。

答案

1:=true

2:=true

3:=false

4:=false

總結(jié)

以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,如果有疑問(wèn)大家可以留言交流,謝謝大家對(duì)腳本之家的支持。

相關(guān)文章

  • Java動(dòng)態(tài)線程池插件dynamic-tp集成過(guò)程淺析

    Java動(dòng)態(tài)線程池插件dynamic-tp集成過(guò)程淺析

    這篇文章主要介紹了Java動(dòng)態(tài)線程池插件dynamic-tp集成過(guò)程,dynamic-tp是一個(gè)輕量級(jí)的動(dòng)態(tài)線程池插件,它是一個(gè)基于配置中心的動(dòng)態(tài)線程池,線程池的參數(shù)可以通過(guò)配置中心配置進(jìn)行動(dòng)態(tài)的修改
    2023-03-03
  • 解析Java中所有錯(cuò)誤和異常的父類java.lang.Throwable

    解析Java中所有錯(cuò)誤和異常的父類java.lang.Throwable

    這篇文章主要介紹了Java中所有錯(cuò)誤和異常的父類java.lang.Throwable,文章中簡(jiǎn)單地分析了其源碼,說(shuō)明在代碼注釋中,需要的朋友可以參考下
    2016-03-03
  • CountDownLatch同步工具類使用詳解

    CountDownLatch同步工具類使用詳解

    這篇文章主要為大家詳細(xì)介紹了CountDownLatch的使用說(shuō)明,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-04-04
  • java?spring?validation?自動(dòng)、手動(dòng)校驗(yàn)

    java?spring?validation?自動(dòng)、手動(dòng)校驗(yàn)

    HibernateValidator簡(jiǎn)化了Java開發(fā)中的參數(shù)校驗(yàn)過(guò)程,提供自動(dòng)和手動(dòng)兩種校驗(yàn)方式,通過(guò)引入相關(guān)依賴并使用@Validated注解,可以實(shí)現(xiàn)自動(dòng)校驗(yàn),手動(dòng)校驗(yàn)則需要使用ValidatorUtils類,此方法有效減少代碼重復(fù),提高開發(fā)效率
    2024-09-09
  • 用Java實(shí)現(xiàn)連連看小游戲

    用Java實(shí)現(xiàn)連連看小游戲

    這篇文章主要為大家詳細(xì)介紹了用Java實(shí)現(xiàn)連連看小游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-05-05
  • SpringBoot使用Nacos動(dòng)態(tài)配置數(shù)據(jù)源的方法

    SpringBoot使用Nacos動(dòng)態(tài)配置數(shù)據(jù)源的方法

    這篇文章主要介紹了SpringBoot使用Nacos動(dòng)態(tài)配置數(shù)據(jù)源的方法,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-03-03
  • SpringBoot中的RestTemplate使用方法詳解

    SpringBoot中的RestTemplate使用方法詳解

    這篇文章主要介紹了SpringBoot中的RestTemplate使用方法詳解,為了方便使用,這里我封裝成一個(gè)工具類來(lái)靜態(tài)調(diào)用RestTemplate,基于SpringBoot2.4.2版本,需要的朋友可以參考下
    2024-01-01
  • 5種解決Java獨(dú)占寫文件的方法

    5種解決Java獨(dú)占寫文件的方法

    這篇文章主要介紹了5種解決Java獨(dú)占寫文件的方法,需要的朋友可以參考下
    2015-12-12
  • JAVAE中servlet的概念及使用示例詳解

    JAVAE中servlet的概念及使用示例詳解

    servlet是一種實(shí)現(xiàn)動(dòng)態(tài)頁(yè)面的技術(shù),他是由tomcat提供給程序員的一組API可以幫助程序員開發(fā)一個(gè)web程序,這篇文章主要介紹了JAVAE中servlet的概念及使用,需要的朋友可以參考下
    2024-05-05
  • java冒泡排序簡(jiǎn)單實(shí)例

    java冒泡排序簡(jiǎn)單實(shí)例

    本文主要介紹了JSONjava冒泡排序?qū)嵗c思路分析。具有一定的參考價(jià)值,下面跟著小編一起來(lái)看下吧
    2017-01-01

最新評(píng)論