浅谈包装类

221 阅读2分钟

一.包装类是基本类型的引用类型形式

直观的感觉就是 更加方便对象的操作 并且包装类和基本类型之间是可以进行自动拆装箱的

同时包装类也提供了一些更好用的方法 可以方便的操作不同类型的数据

二.包装类大多利用了缓存机制(Float Double没有缓存)

这个机制实际上就是利用了设计模式中的【享元模式】

即相同类型的对象 我们只创建有限个 用来共享

缓存机制一方面可以提升性能 一方面可以减少不必要的创建对象

Byte Short Integer Long默认缓存了 [-128,127] 的相应类型的缓存数据

Character 缓存了数值在 [0,127] 范围的缓存数据

Boolean 直接缓存了True False

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 {
        // high value may be configured by property
        int h = 127;
    }
}

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

}

Boolean缓存的源码:

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

超出缓存范围 会创建新的对象 其实缓存范围就是性能和资源之间的权衡

三.为什么说所有整型包装类对象之间值的比较,全部使用 equals 方法比较?

看这个题目 :

Integer i1 = 40;
Integer i2 = new Integer(40);
System.out.println(i1==i2);

Integer i1=40 这一行代码会发生装箱,也就是说这行代码等价于 Integer i1=Integer.valueOf(40) 。因此,i1 直接使用的是缓存中的对象。而Integer i2 = new Integer(40) 会直接创建新的对象

这是阿里巴巴手册建议:

四.自动拆装箱的底层原理

从底层字节码来看以下两行代码对应字节码:

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

    LINENUMBER 8 L1

    ALOAD 0

    BIPUSH 10

    INVOKESTATIC java/lang/Integer.valueOf (I)Ljava/lang/Integer;

    PUTFIELD AutoBoxTest.i : Ljava/lang/Integer;

   L2

    LINENUMBER 9 L2

    ALOAD 0

    ALOAD 0

    GETFIELD AutoBoxTest.i : Ljava/lang/Integer;

    INVOKEVIRTUAL java/lang/Integer.intValue ()I

    PUTFIELD AutoBoxTest.n : I

    RETURN

可以发现 装箱其实就是调用valueOf方法 拆箱是调用xxxValue方法

注意:频繁拆装箱也会影响系统的性能 我们应该避免不必要的拆装箱 对于局部变量优先使用基本类型 对于成员变量尤其是实体类的属性建议使用包装类型