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

Java中自動(dòng)裝箱、拆箱引起的耗時(shí)詳解

 更新時(shí)間:2019年04月07日 15:04:35   作者:veryitman  
這篇文章主要給大家介紹了關(guān)于Java中自動(dòng)裝箱、拆箱引起的耗時(shí)的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用Java具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧

什么是自動(dòng)裝箱,拆箱

先拋出定義,Java中基礎(chǔ)數(shù)據(jù)類(lèi)型與它們的包裝類(lèi)進(jìn)行運(yùn)算時(shí),編譯器會(huì)自動(dòng)幫我們進(jìn)行轉(zhuǎn)換,轉(zhuǎn)換過(guò)程對(duì)程序員是透明的,這就是裝箱和拆箱,裝箱和拆箱可以讓我們的代碼更簡(jiǎn)潔易懂

耗時(shí)問(wèn)題

在說(shuō) Java 的自動(dòng)裝箱和自動(dòng)拆箱之前,我們先看一個(gè)例子。

這個(gè)錯(cuò)誤我在項(xiàng)目中犯過(guò)(尷尬),拿出來(lái)共勉!

private static long getCounterResult() {
 Long sum = 0L;
 final int length = Integer.MAX_VALUE;
 for (int i = 0; i < length; i++) {
 sum += i;
 }
 return sum;
}
public static void main(String[] args) {
 long startCountTime = System.currentTimeMillis();
 long result = getCounterResult();
 long endCountTime = System.currentTimeMillis();
 System.out.println("result = " + result + ", and take up time : " + (endCountTime - startCountTime) / 1000 + "s");
}

在我的電腦(macOS 64位系統(tǒng),配置較高),打印結(jié)果如下:

result = 2305843005992468481, and take up time : 12s

居然使用了 12s,是可忍叔不可忍,再正常不過(guò)的代碼怎么會(huì)耗時(shí)這么久呢?如果在配置差一點(diǎn)的電腦上運(yùn)行耗時(shí)會(huì)更久(驚呆了.jpg)。

我們不妨先閱讀下面的內(nèi)容,再來(lái)分析、解決上述耗時(shí)的問(wèn)題。

基本概念

自從 jdk1.5 之后就有了自動(dòng)裝箱(Autoboxing)和自動(dòng)拆箱(AutoUnboxing)。

自動(dòng)裝箱,就是 Java 自動(dòng)將原始(基本)類(lèi)型轉(zhuǎn)換成對(duì)應(yīng)的封裝器(對(duì)象)類(lèi)型的過(guò)程,比如將 int 的變量轉(zhuǎn)換成 Integer 對(duì)象,這個(gè)過(guò)程叫做裝箱。

自動(dòng)拆箱,就是 Java 自動(dòng)將封裝器(對(duì)象)類(lèi)型轉(zhuǎn)換成基本類(lèi)型的過(guò)程,如將 Integer 對(duì)象轉(zhuǎn)換成 int 類(lèi)型值,這個(gè)過(guò)程叫做拆箱。

之所以稱(chēng)之為自動(dòng)裝箱和拆箱,是因?yàn)檫@些操作并非人工(程序猿)操作的,而是 Java 自帶的一個(gè)特性。

下表是 Java 中的基本類(lèi)型和對(duì)應(yīng)的封裝類(lèi)型的對(duì)應(yīng)表:

基本類(lèi)型 封裝器類(lèi)
int Integer
byte Byte
long Long
float float
double Double
char Character
boolean Boolean

自動(dòng)裝箱示例:

int a = 3;
Integer b = a;

自動(dòng)拆箱示例:

Integer b = new Integer(7);
int a = b;

Integer/int 自動(dòng)拆箱和裝箱

下面這段代碼是 Integer 的源碼中 valueOf 方法。

/**
 * Returns an {@code Integer} instance representing the specified
 * {@code int} value. If a new {@code Integer} instance is not
 * required, this method should generally be used in preference to
 * the constructor {@link #Integer(int)}, as this method is likely
 * to yield significantly better space and time performance by
 * caching frequently requested values.
 *
 * This method will always cache values in the range -128 to 127,
 * inclusive, and may cache other values outside of this range.
 *
 * @param i an {@code int} value.
 * @return an {@code Integer} instance representing {@code i}.
 * @since 1.5
 */
public static Integer valueOf(int i) {
 // 如果i的值大于-128小于127則返回一個(gè)緩沖區(qū)中的一個(gè)Integer對(duì)象
 if (i >= IntegerCache.low && i <= IntegerCache.high)
 return IntegerCache.cache[i + (-IntegerCache.low)];
 
 // 否則返回 new 一個(gè)Integer 對(duì)象
 return new Integer(i);
}

我們?cè)趫?zhí)行下面的這句代碼,如下:

Integer i = 100;

上面的代碼等同于下面的代碼:

Integer i = Integer.valueOf(100);

結(jié)合上面的源碼可以看出來(lái),如果數(shù)值在 [-128,127] 之間(雙閉區(qū)間),不會(huì)重新創(chuàng)建 Integer 對(duì)象,而是從緩存中(常量池)直接獲取,從常量池中獲取而不是堆棧操作,讀取數(shù)據(jù)要快很多。

我們?cè)賮?lái)看一下常見(jiàn)的基礎(chǔ)面試題(請(qǐng)給出打印結(jié)果),如下:

public static void main(String[] args) {
 // ⓵
 Integer a = new Integer(121);
 Integer b = new Integer(121);
 System.out.println(a == b);
 
 // ⓶
 Integer c = 121;
 Integer d = 121;
 System.out.println(c == d);
 
 // ⓷
 Integer e = 129;
 Integer f = 129;
 System.out.println(e == f);
 
 // ⓸
 int g = 50;
 Integer h = new Integer(50);
 System.out.println(g == h);
}

分析結(jié)果:

⓵: false, 兩個(gè)對(duì)象進(jìn)行比較分別指向了不同堆內(nèi)存

⓶: true, 自動(dòng)裝箱且數(shù)值在 [-128,127] 之間(雙閉區(qū)間)

⓷: false, 自動(dòng)裝箱且數(shù)值不在 [-128,127] 之間(雙閉區(qū)間)

⓸: true, 自動(dòng)拆箱且數(shù)值在 [-128,127] 之間(雙閉區(qū)間)

解析耗時(shí)問(wèn)題

類(lèi) Long 對(duì)應(yīng)的也有一個(gè) valueof 方法,源碼如下:

public static Long valueOf(long l) {
 final int offset = 128;
 if (l >= -128 && l <= 127) { // will cache
  return LongCache.cache[(int)l + offset];
 }
 return new Long(l);
}

這個(gè)和 Integer 的很像,道理上面說(shuō)過(guò),這里不再贅述。

在開(kāi)篇的例子中,getCounterResult 方法有下面這句代碼,如下:

Long sum = 0L;

很明顯我們聲明了一個(gè) Long 的對(duì)象 sum,由于自動(dòng)裝箱,這句代碼并沒(méi)有語(yǔ)法上面的錯(cuò)誤,編譯器當(dāng)然也不會(huì)報(bào)錯(cuò)。上面代碼等同于如下代碼:

Long sum = Long.valueof(0);

在 for 循環(huán)中,超過(guò) [-128,127] 就會(huì)創(chuàng)建新的對(duì)象,這樣不斷的創(chuàng)建對(duì)象,不停的申請(qǐng)堆內(nèi)存,程序執(zhí)行自然也就比較耗時(shí)了。

修改一下代碼,如下:

private static long getCounterResult() {
 // 修改為普通的基本類(lèi)型數(shù)據(jù)
 long sum = 0L;
 final int length = Integer.MAX_VALUE;
 for (int i = 0; i < length; i++) {
  sum += i;
 }
 return sum;
}
public static void main(String[] args) {
 long startCountTime = System.currentTimeMillis();
 long result = getCounterResult();
 long endCountTime = System.currentTimeMillis();
 System.out.println("result = " + result + ", and take up time : " + (endCountTime - startCountTime) / 1000 + "s");
}

執(zhí)行時(shí)間大大縮短。

總結(jié)

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

相關(guān)文章

  • IntelliJ IDEA 安裝教程2019.09.23(最新版)

    IntelliJ IDEA 安裝教程2019.09.23(最新版)

    本文通過(guò)圖文并茂的形式給大家介紹了IntelliJ IDEA 安裝教程2019.09.23最新版,非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2019-10-10
  • java List去掉重復(fù)元素的幾種方式(小結(jié))

    java List去掉重復(fù)元素的幾種方式(小結(jié))

    這篇文章主要介紹了java List去掉重復(fù)元素的幾種方式,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-06-06
  • Mybatis枚舉類(lèi)型轉(zhuǎn)換源碼分析

    Mybatis枚舉類(lèi)型轉(zhuǎn)換源碼分析

    在Mybatis的TypeHandlerRegistry中,添加了常用的類(lèi)轉(zhuǎn)換器,其中默認(rèn)的枚舉類(lèi)型轉(zhuǎn)換器是EnumTypeHandler,這篇文章主要介紹了Mybatis枚舉類(lèi)型轉(zhuǎn)換源碼分析,需要的朋友可以參考下
    2024-05-05
  • 學(xué)習(xí)非阻塞的同步機(jī)制CAS

    學(xué)習(xí)非阻塞的同步機(jī)制CAS

    現(xiàn)代的處理器都包含對(duì)并發(fā)的支持,其中最通用的方法就是比較并交換(compare and swap),簡(jiǎn)稱(chēng)CAS。下面我們來(lái)一起學(xué)習(xí)一下吧
    2019-05-05
  • Java獲取網(wǎng)絡(luò)文件并插入數(shù)據(jù)庫(kù)的代碼

    Java獲取網(wǎng)絡(luò)文件并插入數(shù)據(jù)庫(kù)的代碼

    抓取各大網(wǎng)站的數(shù)據(jù)插入數(shù)據(jù)庫(kù),這樣就不用為沒(méi)有數(shù)據(jù)而煩惱了
    2010-06-06
  • SpringCloud服務(wù)之間Feign調(diào)用不會(huì)帶上請(qǐng)求頭header的解決方法

    SpringCloud服務(wù)之間Feign調(diào)用不會(huì)帶上請(qǐng)求頭header的解決方法

    在Spring?Cloud中,使用Feign進(jìn)行服務(wù)之間的調(diào)用時(shí),默認(rèn)情況下是不會(huì)傳遞header的,這篇文章給大家介紹SpringCloud服務(wù)之間Feign調(diào)用不會(huì)帶上請(qǐng)求頭header的解決方法,感興趣的朋友一起看看吧
    2024-01-01
  • IDEA中配置文件格式為UTF-8的操作方法

    IDEA中配置文件格式為UTF-8的操作方法

    這篇文章主要介紹了IDEA中配置文件格式為UTF-8的操作方法,第一個(gè)需要設(shè)置文件編碼格式的位置,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-10-10
  • java中redis增刪查以及清理緩存的案例

    java中redis增刪查以及清理緩存的案例

    這篇文章主要介紹了java中redis增刪查以及清理緩存的案例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2021-02-02
  • Jrebel啟動(dòng)失敗解決方案詳解

    Jrebel啟動(dòng)失敗解決方案詳解

    這篇文章主要介紹了Jrebel啟動(dòng)失敗解決方案詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-07-07
  • 淺析Java中的訪(fǎng)問(wèn)控制權(quán)限

    淺析Java中的訪(fǎng)問(wèn)控制權(quán)限

    這篇文章主要介紹了淺析Java中的訪(fǎng)問(wèn)控制權(quán)限,在Java中,提供了四種訪(fǎng)問(wèn)權(quán)限控制,分別是默認(rèn)訪(fǎng)問(wèn)權(quán)限、public、private以及protected,感興趣的小伙伴們可以參考一下
    2016-02-02

最新評(píng)論