java中基本数据类型对应的包装器类型以及装箱操作和拆箱操作

java装箱操作和拆箱操作的学习

基本数据类型和包装器类型

Java为每种基本数据类型都提供了对应的包装器类型

基本类型 包装器类型
int(4字节) Integer
byte(1字节) Byte
short(2字节 Short
long(8字节) Long
float(4字节) Float
double(8字节) Double
char(2字节) Character
boolean(未定) Boolean

装箱操作和拆箱操作

装箱:基本类型转变为包装器类型的过程。
拆箱:包装器类型转变为基本类型的过程。

//JDK1.5之前是不支持自动装箱和自动拆箱的,定义Integer对象,必须
Integer i = new Integer(8);

//JDK1.5开始,提供了自动装箱的功能,定义Integer对象可以这样
Integer i = 8;//自动装箱
int n = i;//自动拆箱

装箱是通过调用包装器类的 valueOf() 方法实现的
拆箱是通过调用包装器类的 xxxValue() 方法实现的,xxx代表对应的基本数据类型。

例如:
int装箱的时候自动调用Integer的valueOf(int)方法;
Integer拆箱的时候自动调用Integer的intValue方法。

Integer

我们来看下面的问题

Integer i1=127; 
Integer i2=127; 
System.out.println(i1==i2); 

Integer i3=128; 
Integer i4=128; 
System.out.println(i3==i4); 

输出结果:
true
false

原因分析:看下面的源码,Integer的valueOf()方法创建Integer对象的时候,如果数值在[-128,127]之间,便返回指向IntegerCache.cache中已经存在的对象的引用;否则创建一个新的Integer对象。

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

通过观察IntegerCache 的源码我们发现使用的是静态工厂方法维持一个Integer数组,这种思想在很多源码中都有体现,它的好处在于不必每次新建一个对象。

private static class IntegerCache {
        static final int high;
        static final Integer cache[];

        static {
            final int low = -128;

            // high value may be configured by property
            int h = 127;
            if (integerCacheHighPropValue != null) {
                // Use Long.decode here to avoid invoking methods that
                // require Integer's autoboxing cache to be initialized
                int i = Long.decode(integerCacheHighPropValue).intValue();
                i = Math.max(i, 127);
                // Maximum array size is Integer.MAX_VALUE
                h = Math.min(i, Integer.MAX_VALUE - -low);
            }
            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() {}
    }

Double

再看一个问题

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

输出结果:
false
false
原因分析:看下面的源码就知道了

在这里只解释一下为什么Double类的valueOf方法会采用与Integer类的valueOf方法不同的实现。很简单:在某个范围内的整型数值的个数是有限的,而浮点数却不是。

public static Double valueOf(double d) {
        return new Double(d);
    }

Boolean

再看一个问题

Boolean i1 = false;
Boolean i2 = false;
Boolean i3 = true;
Boolean i4 = true;
 
System.out.println(i1==i2);
System.out.println(i3==i4);

输出结果:
true
true

Boolean的valueOf方法的具体实现

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

TRUE 和FALSE是Boolean类中定义的2个静态成员属性:

/**
* The {@code Boolean} object corresponding to the primitive
* value {@code true}.
*/
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);

注意,Integer、Short、Byte、Character、Long这几个类的valueOf方法的实现是类似的。

   Double、Float的valueOf方法的实现是类似的。

Short

public static Short valueOf(short s) {
        final int offset = 128;
        int sAsInt = s;
        if (sAsInt >= -128 && sAsInt <= 127) { // must cache
            return ShortCache.cache[sAsInt + offset];
        }
        return new Short(s);
    }

注意,Integer、Short、Byte、Character、Long这几个类的valueOf方法的实现是类似的。

   Double、Float的valueOf方法的实现是类似的。

Long

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

注意,Integer、Short、Byte、Character、Long这几个类的valueOf方法的实现是类似的。

   Double、Float的valueOf方法的实现是类似的。

Float

public static Float valueOf(float f) {
        return new Float(f);
    }

其它注意事项

1、Boolean 的两个值 true 和 false 都是 cache 在内存中的,无须做任何改造,自己 new Boolean 是另外一块空间。
2、Byte 的 256 个值全部 cache 在内存中,和自己 new Byte 操作得到的对象不是一块空间。
3、Short、Long 两种类型的 cache 范围为-128~127,无法调整最大尺寸,即没有设置,代码中完全写死,如果要扩展,需自己来做。
4、Float、Double 没有 cache,要在实际场景中 cache 需自己操作,例如,在做图纸尺寸时可以将每种常见尺寸记录在内存中。
5、当 Integer 与 int 类型进行比较的时候,会将 Integer 转化为 int 类型来比较(也就是通过调用 intValue()方法返回数字),直接比较数字,在这种情况下是不会出现例子中的问题的。
6、Integer 做“>”、“>=”、“<”、“<=”比较的时候,Integer 会自动拆箱,就是比较它们的数字值。
7、switch case 为选择语句,匹配的时候不会用 equals(),而是直接用“==”。而在 switchcase 语句中,语法层面 case 部分是不能写 Integer 对象的,只能是普通的数字,如果是普通的数字就会将传入的 Integer 自动拆箱,所以它也不会出现例子中的情况。
8、在 JDK 1.7 中,支持对 String 对象的 switch case 操作,这其实是语法糖,在编译后的字节码中依然是 if else 语句,并且是通过 equals()实现的。


参考链接:
https://blog.csdn.net/u012070360/article/details/54574707
https://www.cnblogs.com/dolphin0520/p/3780005.html

上一篇:回溯问题


下一篇:有趣的"=="与"==="