夯實(shí)Java基礎(chǔ)系列2:Java自動(dòng)拆裝箱里隱藏的秘密

本系列文章將整理到我在GitHub上的《Java面試指南》倉(cāng)庫(kù),更多精彩內(nèi)容請(qǐng)到我的倉(cāng)庫(kù)里查看

創(chuàng)新互聯(lián)專注于新化企業(yè)網(wǎng)站建設(shè),響應(yīng)式網(wǎng)站,電子商務(wù)商城網(wǎng)站建設(shè)。新化網(wǎng)站建設(shè)公司,為新化等地區(qū)提供建站服務(wù)。全流程專業(yè)公司,專業(yè)設(shè)計(jì),全程項(xiàng)目跟蹤,創(chuàng)新互聯(lián)專業(yè)和態(tài)度為您提供的服務(wù)

https://github.com/h3pl/Java-Tutorial

喜歡的話麻煩點(diǎn)下Star哈

文章首發(fā)于我的個(gè)人博客:

www.how2playlife.com

本文是微信公眾號(hào)【Java技術(shù)江湖】的《夯實(shí)Java基礎(chǔ)系列博文》其中一篇,本文部分內(nèi)容來(lái)源于網(wǎng)絡(luò),為了把本文主題講得清晰透徹,也整合了很多我認(rèn)為不錯(cuò)的技術(shù)博客內(nèi)容,引用其中了一些比較好的博客文章,如有侵權(quán),請(qǐng)聯(lián)系作者。

該系列博文會(huì)告訴你如何從入門(mén)到進(jìn)階,一步步地學(xué)習(xí)Java基礎(chǔ)知識(shí),并上手進(jìn)行實(shí)戰(zhàn),接著了解每個(gè)Java知識(shí)點(diǎn)背后的實(shí)現(xiàn)原理,更完整地了解整個(gè)Java技術(shù)體系,形成自己的知識(shí)框架。為了更好地總結(jié)和檢驗(yàn)?zāi)愕膶W(xué)習(xí)成果,本系列文章也會(huì)提供部分知識(shí)點(diǎn)對(duì)應(yīng)的面試題以及參考答案。

如果對(duì)本系列文章有什么建議,或者是有什么疑問(wèn)的話,也可以關(guān)注公眾號(hào)【Java技術(shù)江湖】聯(lián)系作者,歡迎你參與本系列博文的創(chuàng)作和修訂。

Java 基本數(shù)據(jù)類型

變量就是申請(qǐng)內(nèi)存來(lái)存儲(chǔ)值。也就是說(shuō),當(dāng)創(chuàng)建變量的時(shí)候,需要在內(nèi)存中申請(qǐng)空間。

內(nèi)存管理系統(tǒng)根據(jù)變量的類型為變量分配存儲(chǔ)空間,分配的空間只能用來(lái)儲(chǔ)存該類型數(shù)據(jù)。

夯實(shí)Java基礎(chǔ)系列2:Java自動(dòng)拆裝箱里隱藏的秘密

因此,通過(guò)定義不同類型的變量,可以在內(nèi)存中儲(chǔ)存整數(shù)、小數(shù)或者字符。

Java 的兩大數(shù)據(jù)類型:

  • 內(nèi)置數(shù)據(jù)類型
  • 引用數(shù)據(jù)類型

內(nèi)置數(shù)據(jù)類型

Java語(yǔ)言提供了八種基本類型。六種數(shù)字類型(四個(gè)整數(shù)型,兩個(gè)浮點(diǎn)型),一種字符類型,還有一種布爾型。

byte:

  • byte 數(shù)據(jù)類型是8位、有符號(hào)的,以二進(jìn)制補(bǔ)碼表示的整數(shù);
  • 最小值是 -128(-2^7);
  • 最大值是 127(2^7-1);
  • 默認(rèn)值是 0;
  • byte 類型用在大型數(shù)組中節(jié)約空間,主要代替整數(shù),因?yàn)?byte 變量占用的空間只有 int 類型的四分之一;
  • 例子:byte a = 100,byte b = -50。

short:

  • short 數(shù)據(jù)類型是 16 位、有符號(hào)的以二進(jìn)制補(bǔ)碼表示的整數(shù)
  • 最小值是 -32768(-2^15);
  • 最大值是 32767(2^15 - 1);
  • Short 數(shù)據(jù)類型也可以像 byte 那樣節(jié)省空間。一個(gè)short變量是int型變量所占空間的二分之一;
  • 默認(rèn)值是 0;
  • 例子:short s = 1000,short r = -20000。

int:

  • int 數(shù)據(jù)類型是32位、有符號(hào)的以二進(jìn)制補(bǔ)碼表示的整數(shù);
  • 最小值是 -2,147,483,648(-2^31);
  • 最大值是 2,147,483,647(2^31 - 1);
  • 一般地整型變量默認(rèn)為 int 類型;
  • 默認(rèn)值是 0 ;
  • 例子:int a = 100000, int b = -200000。

long:

  • long 數(shù)據(jù)類型是 64 位、有符號(hào)的以二進(jìn)制補(bǔ)碼表示的整數(shù);
  • 最小值是 -9,223,372,036,854,775,808(-2^63);
  • 最大值是 9,223,372,036,854,775,807(2^63 -1);
  • 這種類型主要使用在需要比較大整數(shù)的系統(tǒng)上;
  • 默認(rèn)值是 0L;
  • 例子: long a = 100000L,Long b = -200000L。
    “L”理論上不分大小寫(xiě),但是若寫(xiě)成”l”容易與數(shù)字”1”混淆,不容易分辯。所以最好大寫(xiě)。

float:

  • float 數(shù)據(jù)類型是單精度、32位、符合IEEE 754標(biāo)準(zhǔn)的浮點(diǎn)數(shù);
  • float 在儲(chǔ)存大型浮點(diǎn)數(shù)組的時(shí)候可節(jié)省內(nèi)存空間;
  • 默認(rèn)值是 0.0f;
  • 浮點(diǎn)數(shù)不能用來(lái)表示精確的值,如貨幣;
  • 例子:float f1 = 234.5f。

double:

  • double 數(shù)據(jù)類型是雙精度、64 位、符合IEEE 754標(biāo)準(zhǔn)的浮點(diǎn)數(shù);
  • 浮點(diǎn)數(shù)的默認(rèn)類型為double類型;
  • double類型同樣不能表示精確的值,如貨幣;
  • 默認(rèn)值是 0.0d;
  • 例子:double d1 = 123.4。

boolean:

  • boolean數(shù)據(jù)類型表示一位的信息;
  • 只有兩個(gè)取值:true 和 false;
  • 這種類型只作為一種標(biāo)志來(lái)記錄 true/false 情況;
  • 默認(rèn)值是 false;
  • 例子:boolean >

char:

  • char類型是一個(gè)單一的 16 位 Unicode 字符;
  • 最小值是 \u0000(即為0);
  • 最大值是 \uffff(即為65,535);
  • char 數(shù)據(jù)類型可以儲(chǔ)存任何字符;
  • 例子:char letter = ‘A’;。
//8位
byte bx = Byte.MAX_VALUE;
byte bn = Byte.MIN_VALUE;
//16位
short sx = Short.MAX_VALUE;
short sn = Short.MIN_VALUE;
//32位
int ix = Integer.MAX_VALUE;
int in = Integer.MIN_VALUE;
//64位
long lx = Long.MAX_VALUE;
long ln = Long.MIN_VALUE;
//32位
float fx = Float.MAX_VALUE;
float fn = Float.MIN_VALUE;
//64位
double dx = Double.MAX_VALUE;
double dn = Double.MIN_VALUE;
//16位
char cx = Character.MAX_VALUE;
char cn = Character.MIN_VALUE;
//1位
boolean bt = Boolean.TRUE;
boolean bf = Boolean.FALSE;
`127`
`-128`
`32767`
`-32768`
`2147483647`
`-2147483648`
`9223372036854775807`
`-9223372036854775808`
`3.4028235E38`
`1.4E-45`
`1.7976931348623157E308`
`4.9E-324`
`?`
`true`
`false`

引用類型

  • 在Java中,引用類型的變量非常類似于C/C++的指針。引用類型指向一個(gè)對(duì)象,指向?qū)ο蟮淖兞渴且米兞俊_@些變量在聲明時(shí)被指定為一個(gè)特定的類型,比如 Employee、Puppy 等。變量一旦聲明后,類型就不能被改變了。
  • 對(duì)象、數(shù)組都是引用數(shù)據(jù)類型。
  • 所有引用類型的默認(rèn)值都是null。
  • 一個(gè)引用變量可以用來(lái)引用任何與之兼容的類型。
  • 例子:Site site = new Site(“Runoob”)。

Java 常量

常量在程序運(yùn)行時(shí)是不能被修改的。

在 Java 中使用 final 關(guān)鍵字來(lái)修飾常量,聲明方式和變量類似:

final double PI = 3.1415927;

雖然常量名也可以用小寫(xiě),但為了便于識(shí)別,通常使用大寫(xiě)字母表示常量。

字面量可以賦給任何內(nèi)置類型的變量。例如:

byte a = 68;
char a = 'A'

自動(dòng)拆箱和裝箱(詳解)

Java 5增加了自動(dòng)裝箱與自動(dòng)拆箱機(jī)制,方便基本類型與包裝類型的相互轉(zhuǎn)換操作。在Java 5之前,如果要將一個(gè)int型的值轉(zhuǎn)換成對(duì)應(yīng)的包裝器類型Integer,必須顯式的使用new創(chuàng)建一個(gè)新的Integer對(duì)象,或者調(diào)用靜態(tài)方法Integer.valueOf()。

//在Java 5之前,只能這樣做
Integer value = new Integer(10);
//或者這樣做
Integer value = Integer.valueOf(10);
//直接賦值是錯(cuò)誤的
//Integer value = 10;`

在Java 5中,可以直接將整型賦給Integer對(duì)象,由編譯器來(lái)完成從int型到Integer類型的轉(zhuǎn)換,這就叫自動(dòng)裝箱。

`//在Java 5中,直接賦值是合法的,由編譯器來(lái)完成轉(zhuǎn)換`
`Integer value = 10;`
`與此對(duì)應(yīng)的,自動(dòng)拆箱就是可以將包裝類型轉(zhuǎn)換為基本類型,具體的轉(zhuǎn)換工作由編譯器來(lái)完成。`
`//在Java 5 中可以直接這么做`
`Integer value = new Integer(10);`
`int i = value;`

自動(dòng)裝箱與自動(dòng)拆箱為程序員提供了很大的方便,而在實(shí)際的應(yīng)用中,自動(dòng)裝箱與拆箱也是使用最廣泛的特性之一。自動(dòng)裝箱和自動(dòng)拆箱其實(shí)是Java編譯器提供的一顆語(yǔ)法糖(語(yǔ)法糖是指在計(jì)算機(jī)語(yǔ)言中添加的某種語(yǔ)法,這種語(yǔ)法對(duì)語(yǔ)言的功能并沒(méi)有影響,但是更方便程序員使用。通過(guò)可提高開(kāi)發(fā)效率,增加代碼可讀性,增加代碼的安全性)。

實(shí)現(xiàn)

在八種包裝類型中,每一種包裝類型都提供了兩個(gè)方法:

靜態(tài)方法valueOf(基本類型):將給定的基本類型轉(zhuǎn)換成對(duì)應(yīng)的包裝類型;

實(shí)例方法xxxValue():將具體的包裝類型對(duì)象轉(zhuǎn)換成基本類型;
下面我們以int和Integer為例,說(shuō)明Java中自動(dòng)裝箱與自動(dòng)拆箱的實(shí)現(xiàn)機(jī)制。看如下代碼:

class Auto //code1
{
    public static void main(String[] args) 
    {
        //自動(dòng)裝箱
        Integer inte = 10;
        //自動(dòng)拆箱
        int i = inte;
    //再double和Double來(lái)驗(yàn)證一下
    Double doub = 12.40;
    double d = doub;
    }
}

上面的代碼先將int型轉(zhuǎn)為Integer對(duì)象,再講Integer對(duì)象轉(zhuǎn)換為int型,毫無(wú)疑問(wèn),這是可以正確運(yùn)行的。可是,這種轉(zhuǎn)換是怎么進(jìn)行的呢?使用反編譯工具,將生成的Class文件在反編譯為Java文件,讓我們看看發(fā)生了什么:

class Auto//code2
{
  public static void main(String[] paramArrayOfString)
  {
    Integer localInteger = Integer.valueOf(10);
int i = localInteger.intValue();
Double localDouble = Double.valueOf(12.4D);
double d = localDouble.doubleValue();
  }
}

我們可以看到經(jīng)過(guò)javac編譯之后,code1的代碼被轉(zhuǎn)換成了code2,實(shí)際運(yùn)行時(shí),虛擬機(jī)運(yùn)行的就是code2的代碼。也就是說(shuō),虛擬機(jī)根本不知道有自動(dòng)拆箱和自動(dòng)裝箱這回事;在將Java源文件編譯為class文件的過(guò)程中,javac編譯器在自動(dòng)裝箱的時(shí)候,調(diào)用了Integer.valueOf()方法,在自動(dòng)拆箱時(shí),又調(diào)用了intValue()方法。我們可以看到,double和Double也是如此。
實(shí)現(xiàn)總結(jié):其實(shí)自動(dòng)裝箱和自動(dòng)封箱是編譯器為我們提供的一顆語(yǔ)法糖。在自動(dòng)裝箱時(shí),編譯器調(diào)用包裝類型的valueOf()方法;在自動(dòng)拆箱時(shí),編譯器調(diào)用了相應(yīng)的xxxValue()方法。

自動(dòng)裝箱與拆箱中的“坑”

在使用自動(dòng)裝箱與自動(dòng)拆箱時(shí),要注意一些陷阱,為了避免這些陷阱,我們有必要去看一下各種包裝類型的源碼。

Integer源碼

public final class Integer extends Number implements Comparable<Integer> {
    private final int value;
/*Integer的構(gòu)造方法,接受一個(gè)整型參數(shù),Integer對(duì)象表示的int值,保存在value中*/
 public Integer(int value) {
        this.value = value;
 }
/*equals()方法判斷的是:所代表的int型的值是否相等*/
 public boolean equals(Object obj) {
        if (obj instanceof Integer) {
            return value == ((Integer)obj).intValue();
        }
        return false;
}
/*返回這個(gè)Integer對(duì)象代表的int值,也就是保存在value中的值*/
 public int intValue() {
        return value;
 }
 /**
  * 首先會(huì)判斷i是否在[IntegerCache.low,Integer.high]之間
  * 如果是,直接返回Integer.cache中相應(yīng)的元素
  * 否則,調(diào)用構(gòu)造方法,創(chuàng)建一個(gè)新的Integer對(duì)象
  */
 public static Integer valueOf(int i) {
    assert IntegerCache.high >= 127;
    if (i >= IntegerCache.low && i <= IntegerCache.high)
        return IntegerCache.cache[i + (-IntegerCache.low)];
    return new Integer(i);
 }
/**
  * 靜態(tài)內(nèi)部類,緩存了從[low,high]對(duì)應(yīng)的Integer對(duì)象
  * low -128這個(gè)值不會(huì)被改變
  * high 默認(rèn)是127,可以改變,最大不超過(guò):Integer.MAX_VALUE - (-low) -1
  * cache 保存從[low,high]對(duì)象的Integer對(duì)象
 */
 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) {
            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);
        }
        high = h;
        cache = new Integer[(high - low) + 1];
        int j = low;
        for(int k = 0; k < cache.length; k++)
            cache[k] = new Integer(j++);
    }
    private IntegerCache() {}
}

以上是Oracle(Sun)公司JDK 1.7中Integer源碼的一部分,通過(guò)分析上面的代碼,得到:

1)Integer有一個(gè)實(shí)例域value,它保存了這個(gè)Integer所代表的int型的值,且它是final的,也就是說(shuō)這個(gè)Integer對(duì)象一經(jīng)構(gòu)造完成,它所代表的值就不能再被改變。

2)Integer重寫(xiě)了equals()方法,它通過(guò)比較兩個(gè)Integer對(duì)象的value,來(lái)判斷是否相等。

3)重點(diǎn)是靜態(tài)內(nèi)部類IntegerCache,通過(guò)類名就可以發(fā)現(xiàn):它是用來(lái)緩存數(shù)據(jù)的。它有一個(gè)數(shù)組,里面保存的是連續(xù)的Integer對(duì)象。
(a) low:代表緩存數(shù)據(jù)中最小的值,固定是-128。

(b) high:代表緩存數(shù)據(jù)中最大的值,它可以被該改變,默認(rèn)是127。high最小是127,最大是Integer.MAX_VALUE-(-low)-1,如果high超過(guò)了這個(gè)值,那么cache[ ]的長(zhǎng)度就超過(guò)Integer.MAX_VALUE了,也就溢出了。

(c) cache[]:里面保存著從[low,high]所對(duì)應(yīng)的Integer對(duì)象,長(zhǎng)度是high-low+1(因?yàn)橛性?,所以要加1)。

4)調(diào)用valueOf(inti)方法時(shí),首先判斷i是否在[low,high]之間,如果是,則復(fù)用Integer.cache[i-low]。比如,如果Integer.valueOf(3),直接返回Integer.cache[131];如果i不在這個(gè)范圍,則調(diào)用構(gòu)造方法,構(gòu)造出一個(gè)新的Integer對(duì)象。

5)調(diào)用intValue(),直接返回value的值。
通過(guò)3)和4)可以發(fā)現(xiàn),默認(rèn)情況下,在使用自動(dòng)裝箱時(shí),VM會(huì)復(fù)用[-128,127]之間的Integer對(duì)象。

Integer  a1 = 1;
Integer  a2 = 1;
Integer  a3 = new Integer(1);
//會(huì)打印true,因?yàn)閍1和a2是同一個(gè)對(duì)象,都是Integer.cache[129]
System.out.println(a1 == a2);
//false,a3構(gòu)造了一個(gè)新的對(duì)象,不同于a1,a2
System.out.println(a1 == a3);

了解基本類型緩存(常量池)的最佳實(shí)踐

//基本數(shù)據(jù)類型的常量池是-128到127之間。
// 在這個(gè)范圍中的基本數(shù)據(jù)類的包裝類可以自動(dòng)拆箱,比較時(shí)直接比較數(shù)值大小。
public static void main(String[] args) {
    //int的自動(dòng)拆箱和裝箱只在-128到127范圍中進(jìn)行,超過(guò)該范圍的兩個(gè)integer的 == 判斷是會(huì)返回false的。
    Integer a1 = 128;
    Integer a2 = -128;
    Integer a3 = -128;
    Integer a4 = 128;
    System.out.println(a1 == a4);
    System.out.println(a2 == a3);
    Byte b1 = 127;
    Byte b2 = 127;
    Byte b3 = -128;
    Byte b4 = -128;
    //byte都是相等的,因?yàn)榉秶驮?128到127之間
    System.out.println(b1 == b2);
    System.out.println(b3 == b4);
    //
    Long c1 = 128L;
    Long c2 = 128L;
    Long c3 = -128L;
    Long c4 = -128L;
    System.out.println(c1 == c2);
    System.out.println(c3 == c4);
    //char沒(méi)有負(fù)值
    //發(fā)現(xiàn)char也是在0到127之間自動(dòng)拆箱
    Character d1 = 128;
    Character d2 = 128;
    Character d3 = 127;
    Character d4 = 127;
    System.out.println(d1 == d2);
    System.out.println(d3 == d4);
    `結(jié)果`
    `false`
    `true`
    `true`
    `true`
    `false`
    `true`
    `false`
    `true`
    Integer i = 10;
    Byte b = 10;
    //比較Byte和Integer.兩個(gè)對(duì)象無(wú)法直接比較,報(bào)錯(cuò)
    //System.out.println(i == b);
    System.out.println("i == b " + i.equals(b));
    //答案是false,因?yàn)榘b類的比較時(shí)先比較是否是同一個(gè)類,不是的話直接返回false.
    int ii = 128;
    short ss = 128;
    long ll = 128;
    char cc = 128;
    System.out.println("ii == bb " + (ii == ss));
    System.out.println("ii == ll " + (ii == ll));
    System.out.println("ii == cc " + (ii == cc));
    結(jié)果
    i == b false
    ii == bb true
    ii == ll true
    ii == cc true
    //這時(shí)候都是true,因?yàn)榛緮?shù)據(jù)類型直接比較值,值一樣就可以。

總結(jié):

通過(guò)上面的代碼,我們分析一下自動(dòng)裝箱與拆箱發(fā)生的時(shí)機(jī):

(1)當(dāng)需要一個(gè)對(duì)象的時(shí)候會(huì)自動(dòng)裝箱,比如Integer a = 10;equals(Object o)方法的參數(shù)是Object對(duì)象,所以需要裝箱。

(2)當(dāng)需要一個(gè)基本類型時(shí)會(huì)自動(dòng)拆箱,比如int a = new Integer(10);算術(shù)運(yùn)算是在基本類型間進(jìn)行的,所以當(dāng)遇到算術(shù)運(yùn)算時(shí)會(huì)自動(dòng)拆箱,比如代碼中的 c == (a + b);

(3) 包裝類型 == 基本類型時(shí),包裝類型自動(dòng)拆箱;

需要注意的是:“==”在沒(méi)遇到算術(shù)運(yùn)算時(shí),不會(huì)自動(dòng)拆箱;基本類型只會(huì)自動(dòng)裝箱為對(duì)應(yīng)的包裝類型,代碼中最后一條說(shuō)明的內(nèi)容。

在JDK 1.5中提供了自動(dòng)裝箱與自動(dòng)拆箱,這其實(shí)是Java 編譯器的語(yǔ)法糖,編譯器通過(guò)調(diào)用包裝類型的valueOf()方法實(shí)現(xiàn)自動(dòng)裝箱,調(diào)用xxxValue()方法自動(dòng)拆箱。自動(dòng)裝箱和拆箱會(huì)有一些陷阱,那就是包裝類型復(fù)用了某些對(duì)象。

(1)Integer默認(rèn)復(fù)用了[-128,127]這些對(duì)象,其中高位置可以修改;

(2)Byte復(fù)用了全部256個(gè)對(duì)象[-128,127];

(3)Short服用了[-128,127]這些對(duì)象;

(4)Long服用了[-128,127];

(5)Character復(fù)用了[0,127],Charater不能表示負(fù)數(shù);

Double和Float是連續(xù)不可數(shù)的,所以沒(méi)法復(fù)用對(duì)象,也就不存在自動(dòng)裝箱復(fù)用陷阱。

Boolean沒(méi)有自動(dòng)裝箱與拆箱,它也復(fù)用了Boolean.TRUE和Boolean.FALSE,通過(guò)Boolean.valueOf(boolean b)返回的Blooean對(duì)象要么是TRUE,要么是FALSE,這點(diǎn)也要注意。

本文介紹了“真實(shí)的”自動(dòng)裝箱與拆箱,為了避免寫(xiě)出錯(cuò)誤的代碼,又從包裝類型的源碼入手,指出了各種包裝類型在自動(dòng)裝箱和拆箱時(shí)存在的陷阱,同時(shí)指出了自動(dòng)裝箱與拆箱發(fā)生的時(shí)機(jī)。

基本數(shù)據(jù)類型的存儲(chǔ)方式

上面自動(dòng)拆箱和裝箱的原理其實(shí)與常量池有關(guān)。

存在棧中:

public void(int a)
{
int i = 1;
int j = 1;
}
方法中的i 存在虛擬機(jī)棧的局部變量表里,i是一個(gè)引用,j也是一個(gè)引用,它們都指向局部變量表里的整型值 1.
int a是傳值引用,所以a也會(huì)存在局部變量表。

存在堆里:

class A{
int i = 1;
A a = new A();
}
i是類的成員變量。類實(shí)例化的對(duì)象存在堆中,所以成員變量也存在堆中,引用a存的是對(duì)象的地址,引用i存的是值,這個(gè)值1也會(huì)存在堆中。可以理解為引用i指向了這個(gè)值1。也可以理解為i就是1.

3 包裝類對(duì)象怎么存
其實(shí)我們說(shuō)的常量池也可以叫對(duì)象池。
比如String a= new String(“a”).intern()時(shí)會(huì)先在常量池找是否有“a”對(duì)象如果有的話直接返回“a”對(duì)象在常量池的地址,即讓引用a指向常量”a”對(duì)象的內(nèi)存地址。
public native String intern();
Integer也是同理。

下圖是Integer類型在常量池中查找同值對(duì)象的方法。

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() {}
}

所以基本數(shù)據(jù)類型的包裝類型可以在常量池查找對(duì)應(yīng)值的對(duì)象,找不到就會(huì)自動(dòng)在常量池創(chuàng)建該值的對(duì)象。

而String類型可以通過(guò)intern來(lái)完成這個(gè)操作。

JDK1.7后,常量池被放入到堆空間中,這導(dǎo)致intern()函數(shù)的功能不同,具體怎么個(gè)不同法,且看看下面代碼,這個(gè)例子是網(wǎng)上流傳較廣的一個(gè)例子,分析圖也是直接粘貼過(guò)來(lái)的,這里我會(huì)用自己的理解去解釋這個(gè)例子:

[java] view plain copy
String s = new String("1");  
s.intern();  
String s2 = "1";  
System.out.println(s == s2);  
String s3 = new String("1") + new String("1");  
s3.intern();  
String s4 = "11";  
System.out.println(s3 == s4);  
輸出結(jié)果為:
[java] view plain copy
JDK1.6以及以下:false false  
JDK1.7以及以上:false true

夯實(shí)Java基礎(chǔ)系列2:Java自動(dòng)拆裝箱里隱藏的秘密
JDK1.6查找到常量池存在相同值的對(duì)象時(shí)會(huì)直接返回該對(duì)象的地址。

JDK 1.7后,intern方法還是會(huì)先去查詢常量池中是否有已經(jīng)存在,如果存在,則返回常量池中的引用,這一點(diǎn)與之前沒(méi)有區(qū)別,區(qū)別在于,如果在常量池找不到對(duì)應(yīng)的字符串,則不會(huì)再將字符串拷貝到常量池,而只是在常量池中生成一個(gè)對(duì)原字符串的引用。

那么其他字符串在常量池找值時(shí)就會(huì)返回另一個(gè)堆中對(duì)象的地址。

下一節(jié)詳細(xì)介紹String以及相關(guān)包裝類。

具體請(qǐng)見(jiàn): https://blog.csdn.net/a724888/article/details/80042298

關(guān)于Java面向?qū)ο笕筇匦裕?qǐng)參考:

https://blog.csdn.net/a724888/article/details/80033043

參考文章

https://www.runoob.com/java/java-basic-datatypes.html

https://www.cnblogs.com/zch2126/p/5335139.html

https://blog.csdn.net/jreffchen/article/details/81015884

https://blog.csdn.net/yuhongye111/article/details/31850779

微信公眾號(hào)

個(gè)人公眾號(hào):黃小斜

黃小斜是跨考軟件工程的 985 碩士,自學(xué) Java 兩年,拿到了 BAT 等近十家大廠 offer,從技術(shù)小白成長(zhǎng)為阿里工程師。

作者專注于 JAVA 后端技術(shù)棧,熱衷于分享程序員干貨、學(xué)習(xí)經(jīng)驗(yàn)、求職心得和程序人生,目前黃小斜的CSDN博客有百萬(wàn)+訪問(wèn)量,知乎粉絲2W+,全網(wǎng)已有10W+讀者。

黃小斜是一個(gè)斜杠青年,堅(jiān)持學(xué)習(xí)和寫(xiě)作,相信終身學(xué)習(xí)的力量,希望和更多的程序員交朋友,一起進(jìn)步和成長(zhǎng)!

原創(chuàng)電子書(shū):
關(guān)注微信公眾號(hào)【黃小斜】后回復(fù)【原創(chuàng)電子書(shū)】即可領(lǐng)取我原創(chuàng)的電子書(shū)《菜鳥(niǎo)程序員修煉手冊(cè):從技術(shù)小白到阿里巴巴Java工程師》這份電子書(shū)總結(jié)了我2年的Java學(xué)習(xí)之路,包括學(xué)習(xí)方法、技術(shù)總結(jié)、求職經(jīng)驗(yàn)和面試技巧等內(nèi)容,已經(jīng)幫助很多的程序員拿到了心儀的offer!

程序員3T技術(shù)學(xué)習(xí)資源:一些程序員學(xué)習(xí)技術(shù)的資源大禮包,關(guān)注公眾號(hào)后,后臺(tái)回復(fù)關(guān)鍵字 “資料”即可免費(fèi)無(wú)套路獲取,包括Java、python、C++、大數(shù)據(jù)、機(jī)器學(xué)習(xí)、前端、移動(dòng)端等方向的技術(shù)資料。

夯實(shí)Java基礎(chǔ)系列2:Java自動(dòng)拆裝箱里隱藏的秘密

技術(shù)公眾號(hào):Java技術(shù)江湖

如果大家想要實(shí)時(shí)關(guān)注我更新的文章以及分享的干貨的話,可以關(guān)注我的微信公眾號(hào)【Java技術(shù)江湖】

這是一位阿里 Java 工程師的技術(shù)小站。作者黃小斜,專注 Java 相關(guān)技術(shù):SSM、SpringBoot、MySQL、分布式、中間件、集群、Linux、網(wǎng)絡(luò)、多線程,偶爾講點(diǎn)Docker、ELK,同時(shí)也分享技術(shù)干貨和學(xué)習(xí)經(jīng)驗(yàn),致力于Java全棧開(kāi)發(fā)!

(關(guān)注公眾號(hào)后回復(fù)”Java“即可領(lǐng)取 Java基礎(chǔ)、進(jìn)階、項(xiàng)目和架構(gòu)師等免費(fèi)學(xué)習(xí)資料,更有數(shù)據(jù)庫(kù)、分布式、微服務(wù)等熱門(mén)技術(shù)學(xué)習(xí)視頻,內(nèi)容豐富,兼顧原理和實(shí)踐,另外也將贈(zèng)送作者原創(chuàng)的Java學(xué)習(xí)指南、Java程序員面試指南等干貨資源)

Java工程師必備學(xué)習(xí)資源:一些Java工程師常用學(xué)習(xí)資源,關(guān)注公眾號(hào)后,后臺(tái)回復(fù)關(guān)鍵字 “Java”即可免費(fèi)無(wú)套路獲取。

夯實(shí)Java基礎(chǔ)系列2:Java自動(dòng)拆裝箱里隱藏的秘密

?

分享題目:夯實(shí)Java基礎(chǔ)系列2:Java自動(dòng)拆裝箱里隱藏的秘密
網(wǎng)頁(yè)網(wǎng)址:http://m.kartarina.com/article6/pihiig.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供面包屑導(dǎo)航電子商務(wù)軟件開(kāi)發(fā)品牌網(wǎng)站建設(shè)自適應(yīng)網(wǎng)站

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)

成都做網(wǎng)站
主站蜘蛛池模板: 久久精品aⅴ无码中文字字幕重口| 久久久久久无码Av成人影院 | 无码精品国产一区二区三区免费 | 免费a级毛片无码a∨蜜芽试看| 国产精品无码无片在线观看| 亚洲精品中文字幕无码AV| 精品无码日韩一区二区三区不卡| 精品无码AV无码免费专区| 亚洲国产91精品无码专区| 毛片免费全部播放无码| 国产亚洲精品无码专区| 无码人妻精品内射一二三AV | 亚洲精品无码aⅴ中文字幕蜜桃| 日韩av无码成人无码免费| 无码成A毛片免费| 国产精品成人一区无码| 日韩国产成人无码av毛片| 成人免费无码H在线观看不卡 | 无码精品国产一区二区三区免费| 精品久久久久久无码专区不卡| 国产乱子伦精品免费无码专区| 亚洲AV无码久久久久网站蜜桃| 国产丰满乱子伦无码专| 18禁免费无码无遮挡不卡网站| 亚洲自偷自偷偷色无码中文| 国产精品无码免费播放 | 国精品无码一区二区三区左线| 91无码人妻精品一区二区三区L | 无码日韩人妻精品久久| 精品久久久无码21p发布| 亚洲Av永久无码精品三区在线| 国产av永久精品无码| 内射人妻无码色AV天堂| 在线观看亚洲AV每日更新无码| 无码专区久久综合久中文字幕 | 大桥久未无码吹潮在线观看| av无码精品一区二区三区四区| 无码av人妻一区二区三区四区 | 久久精品无码一区二区app| 国产精品无码亚洲一区二区三区 | 国产精品免费无遮挡无码永久视频|