Java 包裝類

包裝類

基本類型 大小 包裝器類型
byte 8bit Byte
short 16bit Short
int 32bit Integer
long 64bit Long
float 32bit Float
double 64bit Double
boolean / Boolean
char 16bit Character
void / Void

其中绝编,前 6 個(gè)類派生于公共的超類 Number。對(duì)象包裝器類是不可變的貌踏,即一旦構(gòu)造了包裝器十饥,就不允許更改包裝在其中的值。同時(shí)祖乳,對(duì)象包裝器類還是 final逗堵,因此不能定義它們的子類

Java 中的包裝器類有兩個(gè)主要的目的:

提供一種機(jī)制,將基本值“包裝”到對(duì)象中眷昆,從而使基本值能夠包含在為對(duì)象而保留的操作中蜒秤,比如添加到 Collections 中,或者從帶對(duì)象返回值的方法中返回亚斋。注意垦藏,Java 5 增加了自動(dòng)裝箱和拆箱,程序員過(guò)去需手工執(zhí)行的許多包裝操作伞访,現(xiàn)在可以由 Java 自動(dòng)處理了

為基本值提供分類功能掂骏。這些功能大多數(shù)于各種轉(zhuǎn)換有關(guān):在基本值和 String 對(duì)象間相互轉(zhuǎn)換,在基本值和 String 對(duì)象之間按不同基數(shù)轉(zhuǎn)換厚掷,如二進(jìn)制弟灼、八進(jìn)制和十六進(jìn)制

類型互轉(zhuǎn)

裝箱和拆箱

裝箱就是自動(dòng)將基本數(shù)據(jù)類型轉(zhuǎn)換為包裝器類型级解;拆箱就是自動(dòng)將包裝器類型轉(zhuǎn)換為基本數(shù)據(jù)類型:

public static void main(String[] args){
    Integer i = 10; //裝箱
    int index = i;  //拆箱
}

反編譯 class 文件之后可以看到:


  • 編譯器在生成類的字節(jié)碼時(shí),插入了必要的方法調(diào)用田绑,而虛擬機(jī)只是執(zhí)行這些字節(jié)碼勤哗。說(shuō)明裝箱和拆箱是編譯器認(rèn)可的,而不是虛擬機(jī)掩驱。

  • 裝箱過(guò)程是通過(guò)調(diào)用包裝器的 valueOf 方法實(shí)現(xiàn)的芒划,而拆箱過(guò)程是通過(guò)調(diào)用包裝器的 xxxValue 方法實(shí)現(xiàn)的。(xxx 代表對(duì)應(yīng)的基本數(shù)據(jù)類型)

注意欧穴,如果在一個(gè)表達(dá)式中混合使用 Integer 和 Double 類型民逼,Integer 值就會(huì)拆箱,提升為 double涮帘,再裝箱為 Double:

Integer n = 1;
Double x = 2.0;
System.out.println(true ? n : x);  // 1.0

相關(guān)問(wèn)題

  • 下面這段代碼的輸出結(jié)果是什么拼苍?
public class Main {
    public static void main(String[] args) {
        Integer i1 = 100;
        Integer i2 = 100;
        Integer i3 = 200;
        Integer i4 = 200;
        
        System.out.println(i1 == i2);
        System.out.println(i3 == i4);
    }
}

結(jié)果:

true
false

這里注意 “== ”和 “equal” 的區(qū)別:

基本類型 == equals
字符串變量 對(duì)象在內(nèi)存中的首地址 字符串內(nèi)容
非字符串變量 對(duì)象在內(nèi)存中的首地址 對(duì)象在內(nèi)存中的首地址
基本類型 不可用
包裝類 地址 內(nèi)容

輸出結(jié)果表明 i1 和 i2 指向的是同一個(gè)對(duì)象,而 i3 和 i4 指向的是不同的對(duì)象调缨。此時(shí)只需一看源碼便知究竟疮鲫,下面這段代碼是 Integer 的 valueOf 方法的具體實(shí)現(xiàn):

public static Integer valueOf(int i) {
    if(i >= -128 && i <= IntegerCache.high)
        return IntegerCache.cache[i + 128];
    else
        return new Integer(i);
}

可以看出,在通過(guò) valueOf 方法創(chuàng)建 Integer 對(duì)象的時(shí)候弦叶,如果數(shù)值在 [-128,127] 之間俊犯,便返回指向 IntegerCache.cache 中已經(jīng)存在的對(duì)象的引用;否則創(chuàng)建一個(gè)新的 Integer 對(duì)象

IntegerCache 源碼:

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

IntegerCache 是一個(gè)工具類伤哺,初始化了 cache燕侠,并將構(gòu)造方法聲明為 private,禁止外部創(chuàng)建

上面的代碼中 i1 和 i2 的數(shù)值為 100默责,因此會(huì)直接從 cache 中取已經(jīng)存在的對(duì)象贬循,所以 i1 和 i2 指向的是同一個(gè)對(duì)象,而 i3 和 i4 則是分別指向不同的對(duì)象

  • 下面這段代碼的輸出結(jié)果是什么桃序?
public class Main {
    public static void main(String[] args) {
        Double i1 = 100.0;
        Double i2 = 100.0;
        Double i3 = 200.0;
        Double i4 = 200.0;
        
        System.out.println(i1 == i2);
        System.out.println(i3 == i4);
    }
}

結(jié)果:

false
false

在某個(gè)范圍內(nèi)的整型數(shù)值的個(gè)數(shù)是有限的杖虾,而浮點(diǎn)數(shù)卻不是。所以 Double 類型沒(méi)有緩存

注意媒熊,Integer奇适、Short、Byte芦鳍、Character嚷往、Long 這幾個(gè)類的 valueOf 方法的實(shí)現(xiàn)是類似的,Double柠衅、Float 的 valueOf 方法的實(shí)現(xiàn)是類似的

  • 下面這段代碼的輸出結(jié)果是什么皮仁?
public class Main {
    public static void main(String[] args) {
        Boolean i1 = false;
        Boolean i2 = false;
        Boolean i3 = true;
        Boolean i4 = true;
         
        System.out.println(i1==i2);
        System.out.println(i3==i4);
    }
}

結(jié)果為:

true
true

至于為什么是這個(gè)結(jié)果,看了 Boolean 類的源碼也會(huì)一目了然:

public static Boolean valueOf(boolean b) {
    return (b ? TRUE : FALSE);
}

public static final Boolean TRUE = new Boolean(true);
    /**
     * The {@code Boolean} object corresponding to the primitive
     * value {@code false}.
     */
public static final Boolean FALSE = new Boolean(false);
  • 下面這段代碼的輸出結(jié)果是什么?
public class Main {
    public static void main(String[] args) {
        Integer a = 1;
        Integer b = 2;
        Integer c = 3;
        Integer d = 3;
        Integer e = 321;
        Integer f = 321;
        Long g = 3L;
        Long h = 2L;

        System.out.println(c == (a + b));
        System.out.println(c.equals(a + b));
        System.out.println(g == (a + b));
        System.out.println(g.equals(a + b));
        System.out.println(g.equals(a + h));
    }
}

注意:當(dāng) “==” 運(yùn)算符的兩個(gè)操作數(shù)都是包裝器類型的引用贷祈,則是比較指向的是否是同一個(gè)對(duì)象趋急,而如果其中有一個(gè)操作數(shù)是表達(dá)式(即包含算術(shù)運(yùn)算)則比較的是數(shù)值(即會(huì)觸發(fā)自動(dòng)拆箱的過(guò)程)。另外势誊,對(duì)于包裝器類型呜达,equals 方法并不會(huì)進(jìn)行類型轉(zhuǎn)換。下面是 Integer 的 equals 方法:

public boolean equals(Object obj) {
    if (obj instanceof Integer) {
        return value == ((Integer)obj).intValue();
    }
    return false;
}

結(jié)果:

true
true
true
false
true

第一句由于 a+b 包含了算術(shù)運(yùn)算粟耻,因此會(huì)觸發(fā)自動(dòng)拆箱過(guò)程(會(huì)調(diào)用 intValue 方法)查近,因此它們比較的是數(shù)值是否相等。

而對(duì)于 c.equals(a+b) 會(huì)先觸發(fā)自動(dòng)拆箱過(guò)程挤忙,再觸發(fā)自動(dòng)裝箱過(guò)程霜威,也就是說(shuō) a+b,會(huì)先各自調(diào)用intValue方法饭玲,得到了加法運(yùn)算后的數(shù)值之后侥祭,便調(diào)用 Integer.valueOf 方法叁执,再進(jìn)行 equals 比較茄厘。

同理對(duì)于后面的也是這樣,不過(guò)要注意倒數(shù)第二個(gè)和最后一個(gè)輸出的結(jié)果(如果數(shù)值是 int 類型的谈宛,裝箱過(guò)程調(diào)用的是 Integer.valueOf次哈;如果是 long 類型的邀跃,裝箱調(diào)用的 Long.valueOf 方法)

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末正歼,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子电爹,更是在濱河造成了極大的恐慌恢筝,老刑警劉巖哀卫,帶你破解...
    沈念sama閱讀 219,110評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異撬槽,居然都是意外死亡此改,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,443評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門侄柔,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)共啃,“玉大人,你說(shuō)我怎么就攤上這事暂题∫萍簦” “怎么了?”我有些...
    開封第一講書人閱讀 165,474評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵薪者,是天一觀的道長(zhǎng)纵苛。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么攻人? 我笑而不...
    開封第一講書人閱讀 58,881評(píng)論 1 295
  • 正文 為了忘掉前任幔虏,我火速辦了婚禮,結(jié)果婚禮上贝椿,老公的妹妹穿的比我還像新娘想括。我一直安慰自己,他們只是感情好烙博,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,902評(píng)論 6 392
  • 文/花漫 我一把揭開白布瑟蜈。 她就那樣靜靜地躺著,像睡著了一般渣窜。 火紅的嫁衣襯著肌膚如雪铺根。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,698評(píng)論 1 305
  • 那天乔宿,我揣著相機(jī)與錄音位迂,去河邊找鬼。 笑死详瑞,一個(gè)胖子當(dāng)著我的面吹牛掂林,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播坝橡,決...
    沈念sama閱讀 40,418評(píng)論 3 419
  • 文/蒼蘭香墨 我猛地睜開眼泻帮,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了计寇?” 一聲冷哼從身側(cè)響起锣杂,我...
    開封第一講書人閱讀 39,332評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎番宁,沒(méi)想到半個(gè)月后元莫,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,796評(píng)論 1 316
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡蝶押,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,968評(píng)論 3 337
  • 正文 我和宋清朗相戀三年踱蠢,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片播聪。...
    茶點(diǎn)故事閱讀 40,110評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡朽基,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出离陶,到底是詐尸還是另有隱情稼虎,我是刑警寧澤,帶...
    沈念sama閱讀 35,792評(píng)論 5 346
  • 正文 年R本政府宣布招刨,位于F島的核電站霎俩,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜打却,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,455評(píng)論 3 331
  • 文/蒙蒙 一杉适、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧柳击,春花似錦猿推、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,003評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至状知,卻和暖如春秽五,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背饥悴。 一陣腳步聲響...
    開封第一講書人閱讀 33,130評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工坦喘, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人西设。 一個(gè)月前我還...
    沈念sama閱讀 48,348評(píng)論 3 373
  • 正文 我出身青樓瓣铣,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親济榨。 傳聞我的和親對(duì)象是個(gè)殘疾皇子坯沪,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,047評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容