Java包装类型

195 阅读2分钟

自动装箱与拆箱

  • 装箱:将基本类型用它们对应的引用类型包装起来;
  • 拆箱:将包装类型转换为基本数据类型;

举例:

Integer i = 10;  //装箱
int n = i;   //拆箱Copy to clipboardErrorCopied

上面这两行代码对应的字节码为:

   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

    RETURNCopy to clipboardErrorCopied

从字节码中,我们发现装箱其实就是调用了 包装类的valueOf()方法,拆箱其实就是调用了 xxxValue()方法。

因此,

  • Integer i = 10 等价于 Integer i = Integer.valueOf(10)
  • int n = i 等价于 int n = i.intValue();

8 种基本类型的包装类和常量池

Java 基本类型的包装类的大部分都实现了常量池技术。Byte,Short,Integer,Long 这 4 种包装类默认创建了数值  [-128,127]  的相应类型的缓存数据,Character 创建了数值在[0,127]范围的缓存数据,Boolean 直接返回 True Or False

Integer 缓存源码:

/**

*此方法将始终缓存-128 到 127(包括端点)范围内的值,并可以缓存此范围之外的其他值。

*/

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[];

}

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

    }

}Copy to clipboardErrorCopied

Boolean 缓存源码:

public static Boolean valueOf(boolean b) {

    return (b ? TRUE : FALSE);

}Copy to clipboardErrorCopied

如果超出对应范围仍然会去创建新的对象,缓存的范围区间的大小只是在性能和资源之间的权衡。

两种浮点数类型的包装类 Float,Double 并没有实现常量池技术。

Integer i1 = 33;

Integer i2 = 33;

System.out.println(i1 == i2);// 输出 true

Float i11 = 333f;

Float i22 = 333f;

System.out.println(i11 == i22);// 输出 false

Double i3 = 1.2;

Double i4 = 1.2;

System.out.println(i3 == i4);// 输出 falseCopy to clipboardErrorCopied

下面我们来看一下问题。下面的代码的输出结果是 true 还是 flase 呢?

Integer i1 = 40;

Integer i2 = new Integer(40);

System.out.println(i1==i2);Copy to clipboardErrorCopied

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

因此,答案是 false 。你答对了吗?

记住:所有整型包装类对象之间值的比较,全部使用 equals 方法比较

image.png