深入理解Java装箱与拆箱

写给小白看的Java基础知识,阅读本文大概需要7分钟

Java中有8种基础数据类型,boolean,char,byte,short,int,
long,float,double。从jdk5开始提供了自动装箱拆箱机制,对应的包装类型即Boolean,Character,Byte,Short,Integer,Long,Float,Double。

首先解释一下为什么要引入装箱和拆箱机制,因为Java是面向对象的语言啊,这样使用了包装类后,就可以调用object的一些方法了。都是个人见解,欢迎指正。

Integer i=10;//装箱
int n=i;//拆箱

装箱就是将基础数据类型转换为对应的包装器类型;
拆箱就是将包装器类型转换为对应的基础数据类型;

那装箱和拆箱是如何实现的呢,其实我们在Integer源码中可以查看,装箱使用了valueOf()方法,拆箱使用了intValue()。


public static Integer valueOf(int i) {
        //low=-128
        if (i >= IntegerCache.low && i <= IntegerCache.high)
            return IntegerCache.cache[i + (-IntegerCache.low)];
        return new Integer(i);
    }
   
 public int intValue() {
        return value;
    } 
 
 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() {}
    }

从上述方法的具体实现可以知道,vauleOf已经在cache中创建了[-128,127]范围的对象数组,当新建的Integer数值在该范围中,会从对象数组里返回相应的对象。如果超出范围会重新创建一个对象。

经过上面的解释我们可以很好地理解上图的结果,i1和i2都在[-128,127]中,所以返回的是同一个对象,结果为true。而i3和i4超出该范围,所以两次都要新建对象,于是结果返回false。

而对于其他几种包装类型,也都是利用对应的vauleOf和(Boolean/Character/Byte/Short/Long/Float/Double)Value方法实现装箱,拆箱。其中Integer、Short、Byte、Character、Long这几个类的valueOf方法的实现是类似的,Double、Float的valueOf方法的实现是类似的,大家可以在源码中查看。

        Integer a = 1;
        Integer b = 2;
        Integer c = 3;
        Integer d = 3;
        Integer e = 200;
        Integer f = 200;
        Long g = 3L;
        Long h = 2L;
​
        System.out.println(c==d);//true
        System.out.println(e==f);//false
        System.out.println(c==(a+b));//true
        System.out.println(c.equals(a+b));//true
        System.out.println(g==(a+b));//true 当==两边有算式时,就比较数值(自动拆箱)
        System.out.println(g.equals(a+b));//false
        System.out.println(g.equals(a+h));//true      

在解释结果前先来说说==euqals的区别:
== : 它的作用是判断两个对象的地址是不是相等。即,判断两个对象是不是同一个对象(基本数据类型比较的是值,引用数据类型比较的是内存地址)。
equals() : 它的作用也是判断两个对象是否相等。但它一般有两种使用情况:
情况 1:类没有覆盖 equals() 方法。则通过 equals() 比较该类的两个对象时,等价于通过“==”比较这两个对象。
情况 2:类覆盖了 equals() 方法。一般,我们都覆盖 equals() 方法来比较两个对象的内容是否相等;若它们的内容相等,则返回 true (即,认为这两个对象相等)。

这里解释一下后三个的结果,==两边如果有算式的话,那就只比较内容而不是地址,结果为true。倒数第二个中,a+b和g的类型不同,自然地址也不相同,结果为false。最后一个a+h结果会发生隐式转换,所以结果为true。

欢迎关注我的公众号预备码农公众号

发布了3 篇原创文章 · 获赞 6 · 访问量 291

猜你喜欢

转载自blog.csdn.net/xchkeepdoing/article/details/105340738