JAVA自动装箱和自动拆箱

自动装箱和自动拆箱

1.摘要

众所周知,java是一门面向对象的编程语言,所以除了8大基础类型之外一切皆为对象,但为了方便面向对象开发,基础类型也有对应的包装类。但包装类和基础类型在赋值或比较时要进行类型转化,使用起来不够丝滑,感觉他们之间有很大的鸿沟。所以jdk1.5之后就推出了自动装箱和自动拆箱机制,使开发更加方便,代码更加简洁。自动装箱就是在编译时自动将基础类型转化与之对应的包装类,而自动拆箱刚好与之相反,就是在编译时自动将包装类转化为与之对应的基础类型。

2.基础类型

基础类型包装类型大小(字节)取值范围默认值缓存范围
byteByte1-27, 27-10-128,127
shortShort2-215, 215-10-128,127
intInteger4-231, 231-10-128,127
longLong8-263, 263-10L-128,127
charCharacter20, 216-1 (\u0000,\uffff)\u00000,127
floatFloat41.4E-45, 3.4028235E380.0f
doubleDouble84.9E-324, 1.7976931348623157E3080.0d
booleanBoolean1true, falsefalsetrue,false

取值范围的计算过程:

对于有符号整型,我们在内存中存的是按照补码来存的,第一位表示符号,1为负数,0为正数。正数的补码为其本身,负数的补码为源码按位取反(反码),末位加1。用补码的好处是方便计算机的运算,计算机只需要用补码按位加就可以计算正负数的加减法。

对于基础类型的取值范围主要跟其大小有关,比如说char共有2字节(Byte),共16位(bit),所以能存储16个二进制位,一个二进制可以表示1或0,所以可以表示216个数,从零开始的话就可以表示到216-1。但有的类型是有正负数的,比如说short,我们要用一位二进制位来表示正负符号,所以就只有15位来表示数值,所以其取值是+0到+215-1,-215-1到-0。+0和-0我们只用+0一个,-0就可多表示一位负数所以其取值范围是-215到215-1

对于浮点数来说有所不同,共有三个部分来表示,及符号位,阶码和尾数三部分组成。单精度共有32位,我们用1位表示符号,8位表示阶码,23位表示尾数。双精度共有64位,我们用1位表示符号,11位表示阶码,52位表示尾数。

3.自动拆箱

自动拆箱就是自动将包装类里对应的基本类型的值返回出来,其实是在编译时自动调用了包装类的xxxValue()方法。我们用包装类给基础类进行赋值、传参或他们之间进行比较(<,>,<=,>=,==)或运算的时候会自动拆箱。

我们可以看一下Integer的源码

private final int value;   
public int intValue() {
        return value;
    }

4.自动装箱

自动装箱就是自动将基本类型转化成与之对应的包装类,其实是系统在编译时自动调用了包装类的valueOf()方法,但需要注意的是装箱时涉及缓存问题,如果该值在缓存范围内就在缓存中取,不在的话就新建一个对象,所以和直接new包装类的对象是不同的。我们用基础类型给包装类进行赋值或传参的时候会自动装箱。

4.1 Integer

由原码可知,Integer是有缓存的,其最小值是-128,最大值默认为127,可由jvm参数配置,如果比127小就取127,最大值和最小值的区间不能超过Integer的容量。

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;//断言,如果IntegerCache.high<127就抛错
    }

    private IntegerCache() {}
}

jvm启动参数配置

-Djava.lang.Integer.IntegerCache.high=XXX;

4.2 Short

由源码可知,Short有缓存,其缓存区间为[-128,127]

    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);
    }
	
    private static class ShortCache {
        private ShortCache(){}

        static final Short cache[] = new Short[-(-128) + 127 + 1];

        static {
            for(int i = 0; i < cache.length; i++)
                cache[i] = new Short((short)(i - 128));
        }
    }

4.3 Long

由源码可知, Long有缓存,其缓存区间为[-128,127]

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);
    }
	
	    private static class LongCache {
        private LongCache(){}

        static final Long cache[] = new Long[-(-128) + 127 + 1];

        static {
            for(int i = 0; i < cache.length; i++)
                cache[i] = new Long(i - 128);
        }
    }

4.4 Byte

由源码可知, Byte有缓存,其缓存区间为[-128,127]

	public static Byte valueOf(byte b) {
        final int offset = 128;
        return ByteCache.cache[(int)b + offset];
    }
	
	private static class ByteCache {
        private ByteCache(){}

        static final Byte cache[] = new Byte[-(-128) + 127 + 1];

        static {
            for(int i = 0; i < cache.length; i++)
                cache[i] = new Byte((byte)(i - 128));
        }
    }

4.5 Character

由源码可知, Character有缓存,其缓存区间为[0,127]([\u0000,\u007F])

Character

    public static Character valueOf(char c) {
        if (c <= 127) { // must cache
            return CharacterCache.cache[(int)c];
        }
        return new Character(c);
    }
	
	private static class CharacterCache {
        private CharacterCache(){}

        static final Character cache[] = new Character[127 + 1];

        static {
            for (int i = 0; i < cache.length; i++)
                cache[i] = new Character((char)i);
        }
    }
	

4.6 Boolean

由源码可知, Boolean有缓存,其缓存值为true和false

 public static final Boolean TRUE = new Boolean(true);
 public static final Boolean FALSE = new Boolean(false);
 
 public static Boolean valueOf(boolean b) {
 	return (b ? TRUE : FALSE);
 }

4.7 Float

由源码可知,Float无缓存

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

4.8 Double

由源码可知,Double无缓存

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

5.思考

(1)浮点数为什么没有缓存

因为在一个指定的区间内有无数个浮点数

(2)判断以下程序得到输出结果

Integer a=new Integer(10);//新建对象
Integer b=new Integer(10);//新建对象
int c=10;
System.out.println(a==b);//false,不是同一个对象
System.out.println(a.equals(b));//true,两个对象的内容相同
System.out.println(a==c);//自动拆箱,true
System.out.println(b==c);//自动拆箱,true
Integer d=10; //自动装箱取缓存对象
Integer e=10;
System.out.println(d==e); //true,d、e指向的是从缓存中取的同一个对象
Integer g=128;
Integer h=128;
System.out.println(g==h);//false,自动装箱,由于该值不在缓存范围内,所以新建了两个对象
System.out.println(0.1+0.2==0.3);//false,有的小数转化为二进制会丢失精度,所以计算出的结果不是0.3
  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值