溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶(hù)服務(wù)條款》

Java包裝類(lèi)怎么應(yīng)用

發(fā)布時(shí)間:2022-04-07 09:57:26 來(lái)源:億速云 閱讀:125 作者:iii 欄目:開(kāi)發(fā)技術(shù)

這篇文章主要介紹“Java包裝類(lèi)怎么應(yīng)用”的相關(guān)知識(shí),小編通過(guò)實(shí)際案例向大家展示操作過(guò)程,操作方法簡(jiǎn)單快捷,實(shí)用性強(qiáng),希望這篇“Java包裝類(lèi)怎么應(yīng)用”文章能幫助大家解決問(wèn)題。

    一、包裝類(lèi)概述

    Java有8種基本數(shù)據(jù)類(lèi)型:整型(byte、short、int、long)、浮點(diǎn)型(float、double)、布爾型boolean、字符型char,相對(duì)應(yīng)地,Java提供了8種包裝類(lèi)Byte、Short、Integer、Long、Float、Double、Boolean、Character。包裝類(lèi)創(chuàng)建對(duì)象的方式就跟其他類(lèi)一樣。

    Integer num = new Integer(0);    //創(chuàng)建一個(gè)數(shù)值為0的Integer對(duì)象

    二、包裝類(lèi)的自動(dòng)裝箱、自動(dòng)拆箱機(jī)制 

    上面的構(gòu)造對(duì)象語(yǔ)句實(shí)際上是基本數(shù)據(jù)類(lèi)型向包裝類(lèi)的轉(zhuǎn)換。在應(yīng)用中我們經(jīng)常需要進(jìn)行基本類(lèi)型數(shù)據(jù)和包裝類(lèi)對(duì)象之間的互轉(zhuǎn)。

    Integer num1 = new Integer(1);	//基本數(shù)據(jù)類(lèi)型轉(zhuǎn)為包裝類(lèi)
    int num2 = num1.intValue();		//包裝類(lèi)型轉(zhuǎn)為基本數(shù)據(jù)類(lèi)型
    System.out.println(num1 +"	"+ num2);

    而Java為了方便我們使用,以及出于其他目的如性能調(diào)優(yōu),給我們提供了自動(dòng)裝箱、拆箱機(jī)制。這種機(jī)制簡(jiǎn)化了基本類(lèi)型和包裝類(lèi)型的轉(zhuǎn)換。

    //1、包裝類(lèi)中的自動(dòng)裝箱拆箱機(jī)制
    Integer  num1 = 1;		//自動(dòng)裝箱
    int num2 = num1;		//自動(dòng)拆箱
    System.out.println(num1 +"	"+ num2);

    當(dāng)使用jad工具對(duì)上面的代碼進(jìn)行反編譯時(shí),結(jié)果如下。

    Integer integer = Integer.valueOf(1);
    int i = integer.intValue();
    System.out.println((new StringBuilder()).append(integer).append("\t").append(i).toString());

    可見(jiàn),Java編譯器幫我們完成了轉(zhuǎn)換操作。另外,我們可以看到,除了使用new關(guān)鍵字,還可以使用Integer類(lèi)的valueOf()方法創(chuàng)建一個(gè)Integer對(duì)象。這兩個(gè)方式是有所區(qū)別的,我們下面會(huì)說(shuō)到。

    三、包裝類(lèi)中的緩存機(jī)制

    前面說(shuō)到創(chuàng)建包裝類(lèi)對(duì)象有兩種方式:new關(guān)鍵字、valueOf()方法。我們來(lái)看一段代碼感受一下它們的區(qū)別。

    //2、包裝類(lèi)中的緩存機(jī)制
    Integer num3 = 10;
    Integer num4 = 10;
    Integer num5 = new Integer(20);
    Integer num6 = new Integer(20);
    Integer num7 = 128;
    Integer num8 = 128;
    System.out.println((num3==num4) +"	"+ num3.equals(num4));
    System.out.println((num5==num6) +"	"+ num5.equals(num6));
    System.out.println((num7==num8) +"	"+ num7.equals(num8));

    運(yùn)行結(jié)果為

    Java包裝類(lèi)怎么應(yīng)用

    我們看下它的反編譯代碼

    Integer integer = Integer.valueOf(10);
    Integer integer1 = Integer.valueOf(10);
    Integer integer2 = new Integer(20);
    Integer integer3 = new Integer(20);
    Integer integer4 = Integer.valueOf(128);
    Integer integer5 = Integer.valueOf(128);
    System.out.println((new StringBuilder()).append(integer == integer1).append("\t").append(integer.equals(integer1)).toString());
    System.out.println((new StringBuilder()).append(integer2 == integer3).append("\t").append(integer2.equals(integer3)).toString());
    System.out.println((new StringBuilder()).append(integer4 == integer5).append("\t").append(integer4.equals(integer5)).toString());

    首先,我們查看Integer的valueOf()方法的源碼

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

    再查看下Integer的內(nèi)部類(lèi)IntegerCache的cache數(shù)組成員、low、high成員

            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;
            }

    可以發(fā)現(xiàn),只要Integer類(lèi)第一次被使用到,Integer的靜態(tài)內(nèi)部類(lèi)就被加載,加載的時(shí)候會(huì)創(chuàng)建-128到127的Integer對(duì)象,同時(shí)創(chuàng)建一個(gè)數(shù)組cache來(lái)緩存這些對(duì)象。當(dāng)使用valueOf()方法創(chuàng)建對(duì)象時(shí),就直接返回已經(jīng)緩存的對(duì)象,也就是說(shuō)不會(huì)再新建對(duì)象;當(dāng)使用new關(guān)鍵字or使用valueOf()方法創(chuàng)建小于-128大于127的值對(duì)象時(shí),就會(huì)創(chuàng)建新對(duì)象。

    //2、包裝類(lèi)中的緩存機(jī)制
    Integer num3 = 10;
    Integer num4 = 10;
    Integer num5 = new Integer(20);
    Integer num6 = new Integer(20);
    Integer num7 = 128;
    Integer num8 = 128;

    由于num3、num4都小于等于127,它們指向的是同一個(gè)緩存的Integer對(duì)象,所以用==進(jìn)行比較的結(jié)果是true;num5、num6由于使用new關(guān)鍵字指向的是兩個(gè)不同的新對(duì)象,結(jié)果為false;num7、num8雖然是采用自動(dòng)裝箱的方式,但執(zhí)行valueOf()方法的時(shí)候,由于不滿(mǎn)足條件i >= IntegerCache.low && i <= IntegerCache.high,而同樣新建了兩個(gè)不同的新對(duì)象,結(jié)果同樣是false。

    接著,我們?cè)賮?lái)看看源碼中Integer的equals()方法的實(shí)現(xiàn)

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

    可見(jiàn)equals()方法比較的是Integer對(duì)象的值,而不是像==一樣比較的是對(duì)象是否是同一個(gè)對(duì)象。所以,當(dāng)需要比較兩個(gè)Integer對(duì)象的值是否相等時(shí),記住要用equals()方法。用==比較的話(huà)由于緩存機(jī)制的存在,可能產(chǎn)生一些讓人困擾的結(jié)果。

    此外,在8種包裝類(lèi)型中,有緩存區(qū)的有Character、Byte、Short、Integer、Long,而且它們的實(shí)現(xiàn)方式基本一樣,都是-128到127的緩存范圍。Boolean雖然沒(méi)有緩存區(qū),但是因?yàn)橹挥袃蓚€(gè)值true、false,所以Boolean在成員變量中就創(chuàng)建了兩個(gè)相應(yīng)的對(duì)象。沒(méi)有緩存區(qū)的只有Float、Double,之所以沒(méi)有原因很簡(jiǎn)單,即便是0到1這么小的范圍,浮點(diǎn)數(shù)也有無(wú)數(shù)個(gè),使用緩存區(qū)緩存它們不具備可能性和實(shí)用性。

    緩存區(qū)的存在使得常用的包裝類(lèi)對(duì)象可以得到復(fù)用,這有利于提升性能。當(dāng)我們需要?jiǎng)?chuàng)建新對(duì)象的時(shí)候再new一個(gè),增加了靈活性。

    四、包裝類(lèi)的四則運(yùn)算、位運(yùn)算、比較運(yùn)算、邏輯運(yùn)算

    1、四則運(yùn)算和位運(yùn)算

    //四則運(yùn)算、位運(yùn)算
    Integer num9 = 1;
    Integer num10 = 2;
    Integer num11 = num9 + num10; 
    Short num12 = 5;
    Integer num13 = num9 + num12;
    Long num14 = num9 + 10L;
    System.out.println(num9 << 1);	//位運(yùn)算
    System.out.println(num9 +"	"+ num10 +"	"+ num11 +"	"+ num12 +"	"+ num13 +"	"+ num14);

    Java包裝類(lèi)怎么應(yīng)用

    反編譯結(jié)果如下

            Integer integer = Integer.valueOf(1);
            Integer integer1 = Integer.valueOf(2);
            Integer integer2 = Integer.valueOf(integer.intValue() + integer1.intValue());
            Short short1 = Short.valueOf((short)5);
            Integer integer3 = Integer.valueOf(integer.intValue() + short1.shortValue());
            Long long1 = Long.valueOf((long)integer.intValue() + 10L);
            System.out.println(integer.intValue() << 1);
            System.out.println((new StringBuilder()).append(integer).append("\t").append(integer1).append("\t").append(integer2).append("\t").append(short1).append("\t").append(integer3).append("\t").append(long1).toString());

    可以看到Integer num11 = num9 + num10; 這一句被劃分為3個(gè)步驟:將兩個(gè)Integer對(duì)象分別進(jìn)行拆箱;將拆箱得到的兩個(gè)int數(shù)值相加求其和;將和值進(jìn)行裝箱,從而將num11指向緩存數(shù)組中值為3的Integer對(duì)象。

    而Short num12 = 5; 這一句則先將5強(qiáng)制轉(zhuǎn)換成short類(lèi)型,再將其裝箱把值為5的Short對(duì)象的引用賦給num12。

    而Integer num13 = num9 + num12; 這一句除了Integer num11 = num9 + num10;的3個(gè)步驟,中間還有short+int=int的類(lèi)型自動(dòng)提升的過(guò)程。

    而Long num14 = num9 + 10L; 這一句Integer num11 = num9 + num10;的3個(gè)步驟,中間還有強(qiáng)制類(lèi)型轉(zhuǎn)換的過(guò)程。需要注意的是,如果是Long num14 = num9 + num10; 的話(huà)就會(huì)出現(xiàn)類(lèi)型不匹配的錯(cuò)誤,因?yàn)閚um9、num10拆箱之后相加的和是int類(lèi)型,而Long.valueOf(long)需要的形參是long類(lèi)型,自然會(huì)出錯(cuò)。我們也可以看到,當(dāng)包裝類(lèi)型對(duì)象和基本類(lèi)型數(shù)據(jù)進(jìn)行四則運(yùn)算的時(shí)候,對(duì)象是會(huì)被拆箱的,然后再按基本類(lèi)型數(shù)據(jù)的運(yùn)算規(guī)則進(jìn)行運(yùn)算。

    另外,如果僅僅是打印兩個(gè)包裝類(lèi)型對(duì)象求和的結(jié)果,是不會(huì)有將和值重新轉(zhuǎn)換成該包裝類(lèi)型的步驟的,如下面所示

    System.out.println(num9 + num10);
    System.out.println(integer.intValue() + integer1.intValue());

    這里還需要注意一點(diǎn),盡管基本類(lèi)型與自動(dòng)類(lèi)型提升/強(qiáng)制類(lèi)型轉(zhuǎn)換,包裝類(lèi)是沒(méi)有類(lèi)似的用法的。下面的做法是錯(cuò)的。

    Short num3 = 10;
    Integer num4 = num3;	//錯(cuò)誤: 不兼容的類(lèi)型: Short無(wú)法轉(zhuǎn)換為Integer
    Long num5 = (Long)num4;	//錯(cuò)誤: 不兼容的類(lèi)型: Integer無(wú)法轉(zhuǎn)換為L(zhǎng)ong
    Double num6 = num5;	//錯(cuò)誤: 不兼容的類(lèi)型: Long無(wú)法轉(zhuǎn)換為Double

    小結(jié):不同包裝類(lèi)型對(duì)象是不能直接轉(zhuǎn)換的,不過(guò)有兩種途徑可以代替:一種是上面討論的不同包裝類(lèi)對(duì)象進(jìn)行四則運(yùn)算后賦給某一種類(lèi)型;另一種就是利用包裝類(lèi)的方法

    Integer a = 20;
    Long b = a.longValue();
    Short c = b.shortValue();
    System.out.println(a +"	"+ b +"	"+ c);

    2、比較運(yùn)算和邏輯運(yùn)算

    Integer num9 = 100;
    Integer num10 = 200;
    Short num11 = 50;
    Long num12 = 50L;
    System.out.println((num9<num10) +"	"+ (num9<200) +"	"+ (num9<num11) +"	"+ (num9<num12) +"	"+ (num9<10L));

    反編譯結(jié)果為

    Integer integer = Integer.valueOf(100);
    Integer integer1 = Integer.valueOf(200);
    Short short1 = Short.valueOf((short)50);
    Long long1 = Long.valueOf(50L);
    System.out.println((new StringBuilder()).append(integer.intValue() < integer1.intValue()).append("\t").append(integer.intValue() < 200).append("\t").append(integer.intValue() < short1.shortValue()).append("\t").append((long)integer.intValue() < long1.longValue()).append("\t").append((long)integer.intValue() < 10L).toString());

    可以看到,兩個(gè)同類(lèi)型的包裝類(lèi)對(duì)象進(jìn)行比較時(shí)比較的其實(shí)是各自的基本類(lèi)型數(shù)值,如num9 < num10;兩個(gè)不同類(lèi)型的包裝類(lèi)對(duì)象進(jìn)行比較時(shí)則在比較基本類(lèi)型數(shù)值之前,會(huì)有類(lèi)型提升or強(qiáng)制類(lèi)型轉(zhuǎn)換,如num9 < num11,num9 < num12。

    當(dāng)想比較兩個(gè)對(duì)象是否相等時(shí),注意要使用equals()方法,從前面的討論也知道,使用==的話(huà)比較的其實(shí)是引用的對(duì)象是否同一個(gè),一般不滿(mǎn)足我們的需求。

    Integer num13 = new Integer(100);
    System.out.println(num9.equals(num13) +"	"+ num9.equals(50));

    反編譯結(jié)果為

    Integer integer2 = new Integer(100);
    System.out.println((new StringBuilder()).append(integer.equals(integer2)).append("\t").append(integer.equals(Integer.valueOf(50))).toString());

    邏輯運(yùn)算舉例:

    System.out.println((num9&1));

    反編譯結(jié)果為

    System.out.println(integer.intValue() & 1);

    五、包裝類(lèi)作為方法的形參、返回值

    //包裝類(lèi)作為方法的形參、返回值
    	public static Integer intToInteger(int i) {
    		return i;
    	}  
    	public static int integerToInt(Integer i) {
    		return i;
    	}

    反編譯結(jié)果為

        public static Integer intToInteger(int i)
        {
            return Integer.valueOf(i);
        }
     
        public static int integerToInt(Integer integer)
        {
            return integer.intValue();
        }

    六、包裝類(lèi)作為集合的元素

    //包裝類(lèi)作為集合元素
    List list = new ArrayList();
    list.add(1);
    list.add(new Object());
    Iterator it = list.iterator();
    while (it.hasNext()) {
    	System.out.println(it.next());
    }

    反編譯結(jié)果為

    ArrayList arraylist = new ArrayList();
    arraylist.add(Integer.valueOf(1));
    arraylist.add(new Object());
    for(Iterator iterator = arraylist.iterator(); iterator.hasNext(); System.out.println(iterator.next()));

    可以發(fā)現(xiàn),雖然集合元素要求是對(duì)象,add()方法的形參也是對(duì)象(public boolean add(E e)),但由于自動(dòng)裝箱,基本數(shù)據(jù)類(lèi)型也可以直接加入集合中。

                    List<Integer> list = new ArrayList<>();
    		for (int i=0; i<5; i++) {
    			list.add(i);
    		}
    		Iterator it = list.iterator();
    		while (it.hasNext()) {
    			System.out.println(it.next());
    		}

    反編譯結(jié)果為

            ArrayList arraylist = new ArrayList();
            for(int i = 0; i < 5; i++)
                arraylist.add(Integer.valueOf(i));
     
            for(Iterator iterator = arraylist.iterator(); iterator.hasNext(); System.out.println(iterator.next()));

    七、包裝類(lèi)使用過(guò)程中有可能引起的空指針異常

    //注意包裝類(lèi)可能產(chǎn)生的空引用異常
    		Boolean flag1 = false;
    		System.out.println(flag1?"命題為真":"命題為假");
    		Boolean flag2 = null;
    		System.out.println(flag2?"命題為真":"命題為假");
    		Boolean flag3 = true;

    運(yùn)行結(jié)果為

    Java包裝類(lèi)怎么應(yīng)用

    這里只是簡(jiǎn)單演示空指針異常。平時(shí)使用時(shí)需要注意這一點(diǎn),比如當(dāng)Boolean的對(duì)象作為形參時(shí),在方法執(zhí)行體的頭部需要做下null檢測(cè)。

    上述代碼的反編譯結(jié)果為

            Boolean boolean1 = Boolean.valueOf(false);
            System.out.println(boolean1.booleanValue() ? "\u547D\u9898\u4E3A\u771F" : "\u547D\u9898\u4E3A\u5047");
            Boolean boolean2 = null;
            System.out.println(boolean2.booleanValue() ? "\u547D\u9898\u4E3A\u771F" : "\u547D\u9898\u4E3A\u5047");
            Boolean boolean3 = Boolean.valueOf(true);

    可見(jiàn)三目運(yùn)算符的條件表達(dá)式的位置一定是boolean值,如果你傳入的是Boolean對(duì)象,則會(huì)自動(dòng)拆箱轉(zhuǎn)換為boolean值。

    另外,三目運(yùn)算符的其他兩個(gè)表達(dá)式位置也是如此,會(huì)把包裝類(lèi)對(duì)象轉(zhuǎn)換為相應(yīng)的基本類(lèi)型對(duì)象。

    八、為什么需要包裝類(lèi)?有了包裝類(lèi)又為什么要保留基本數(shù)據(jù)類(lèi)型?(包裝類(lèi)的優(yōu)缺點(diǎn))

    為什么需要包裝類(lèi)?

    首先,Java語(yǔ)言是一個(gè)面向?qū)ο蟮恼Z(yǔ)言,但是Java中的基本數(shù)據(jù)類(lèi)型卻是不面向?qū)ο蟮?,將每個(gè)基本數(shù)據(jù)類(lèi)型設(shè)計(jì)一個(gè)對(duì)應(yīng)的類(lèi)進(jìn)行代表,這種方式增強(qiáng)了Java面向?qū)ο蟮男再|(zhì)。

    其次,如果僅僅有基本數(shù)據(jù)類(lèi)型,那么在實(shí)際使用時(shí)將存在很多的不便,很多地方都需要使用對(duì)象而不是基本數(shù)據(jù)類(lèi)型。比如,在集合類(lèi)中,我們是無(wú)法將int 、double等類(lèi)型放進(jìn)去的,因?yàn)榧系娜萜饕笤厥荗bject類(lèi)型。而包裝類(lèi)型的存在使得向集合中傳入數(shù)值成為可能,包裝類(lèi)的存在彌補(bǔ)了基本數(shù)據(jù)類(lèi)型的不足。

    此外,包裝類(lèi)還為基本類(lèi)型添加了屬性和方法,豐富了基本類(lèi)型的操作。如當(dāng)我們想知道int取值范圍的最小值,我們需要通過(guò)運(yùn)算,如下面所示,但是有了包裝類(lèi),我們可以直接使用Integer.MAX_VALUE即可。

    //求int的最大值
    int max = 0;
    int flag = 1;
    for (int i=0; i<31; i++) {
    	max += flag;
    	flag = flag << 1;
    }
    System.out.println(max +"	"+ Integer.MAX_VALUE); //2147483647      2147483647

    為什么要保留基本數(shù)據(jù)類(lèi)型?

    我們都知道在Java語(yǔ)言中,用new關(guān)鍵字創(chuàng)建的對(duì)象是存儲(chǔ)在堆里的,我們通過(guò)棧中的引用來(lái)使用這些對(duì)象,所以,對(duì)象本身來(lái)說(shuō)是比較消耗資源的。對(duì)于經(jīng)常用到的類(lèi)型,如int等,如果我們每次使用這種變量的時(shí)候都需要new一個(gè)對(duì)象的話(huà),就會(huì)比較笨重了。所以,Java提供了基本數(shù)據(jù)類(lèi)型,這種數(shù)據(jù)的變量不需要使用new在堆上創(chuàng)建,而是直接在棧內(nèi)存中存儲(chǔ),因此會(huì)更加高效。

    關(guān)于“Java包裝類(lèi)怎么應(yīng)用”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識(shí),可以關(guān)注億速云行業(yè)資訊頻道,小編每天都會(huì)為大家更新不同的知識(shí)點(diǎn)。

    向AI問(wèn)一下細(xì)節(jié)

    免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

    AI