包装类

 1 包装类 & 装箱与拆箱

1.1 基本数据类型 & 包装器

  •  基本数据类型及其包装器:

  • 拆箱与装箱: 自动装箱是将基本数据类型转换为其包装类, 自动拆箱是将包装类调用其方法转换为基本数据类型

2. int类型的拆箱与装箱

 2.1 实例

 1     @Test
 2     public void testEquals() {
 3         int int1 = 12;
 4         int int2 = 12;
 5 
 6         Integer integer1 = new Integer(12);
 7         Integer integer2 = new Integer(12);
 8         Integer integer3 = new Integer(127);
 9 
10         Integer a1 = 127;   //或者写成Integer a1 = Integer.valueOf(127);
11         Integer a2 = 127;   //或者写成Integer a2 = Integer.valueOf(127);
12 
13         Integer a = 128;
14         Integer b = 128;
15 
16         System.out.println("int1 == int2 -> " + (int1 == int2));        // true
17         System.out.println("int1 == integer1 -> " + (int1 == integer1));    // true
18         System.out.println("integer1 == integer2 -> " + (integer1 == integer2));    // false
19         System.out.println("integer3 == a1 -> " + (integer3 == a1));    // false
20         System.out.println("a1 == a2 -> " + (a1 == a2));        // true
21         System.out.println("a == b -> " + (a == b));    // false
22     }

  看其反汇编(javap -c class全类名)

  • 主要的汇编指令
  1. bipush num: byte型常量num入栈
  2. istore_index: 栈顶值出栈赋予第index个局部变量(类型为int)
  3. astore_index: 栈顶值出栈赋予第index个局部变量(类型为引用)
  4. sipush num: 将short型常量num入栈
  5. iload_index: 将第index个局部变量入栈(类型为int)
  6. iconst_num: 将int型常量num入栈
  7. aload_index: 将第index个局部变量入栈(类型为引用)

2.2 分析

  1.  6~33行是使用构造函数new Integer(num)创建的,直接调用其构造函数
  2. 38~66行是直接将int常量值赋予Integer变量,可见编译器处理后变成调用valueOf(num)返回Integer引用,再赋予我们的Integer变量[会在后边说,自己也可先看源码实现]
  3. P1(第一个println),int类型比较直接比较其值
  4. P2,int与Integer比较是先调用Integer变量的intValue()获取其int值,再进行ini与int的值比较
  5. P3,Integer与Integer变量均为引用, 因此比较也是比较引用(是否指向同一个对象)

2.3 解析

   构造函数就不说了,不过Integer的有参构造函数被标注在Java9之后全部过时(参数为int或String)

  valueOf引用问题, P5同样是比较引用,但却返回true,P6同样是比较引用,而且和P5一样是直接赋予int常量的,却返回false

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

  valueOf并不是直接返回Integer引用,而是先在缓存里找一找,如果有,则返回已存在的引用,否则返回新对象,IntegerCache是一个static内部类

 

 private static class IntegerCache {
        static final int low = -128;
        static final int high;    // 在low与high范围内通过valueOf创建的会被缓存
        static final Integer[] cache;        // 指向archivedCache
        static Integer[] archivedCache;    //缓存数组,初始化块里就会将low~high的Integer对象创建并存储
    // 不明白为什么有两个cache,archivedCache并没有使用private修饰

  high的大小,根据源码来说应该是在启动之前配置的,可以通过jdk.internal.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");获得,返回String,但是报以下错误

cannot access class jdk.internal.misc.VM (in module java.base) because module java.base does not export jdk.internal.misc to unnamed module @0x2ff4acd0

  可以编译通过,上述错误是运行时报的错误。那就只能使用反射来获取了

Class integerClass = Integer.class;
Class[] classes = integerClass.getDeclaredClasses();
Field hight = classes[0].getDeclaredField("high");
hight.setAccessible(true);
System.out.println(hight.get(null));

  注:异常啥的为了方便不处理了

2.4 对象池

   上述的对象缓存的问题叫做对象池(参考别人博客的),只有Float和Double没有对象池(可以理解),Integer的对象池默认-128~127, Boolean的对象池为true & false,Byte、Short、Long对象池-128~127,Character为0~127

 

3. Integer源码分析

 3.1 继承链

public final class Integer extends Number
        implements Comparable<Integer>, Constable, ConstantDesc

  注:常用不可被继承类(final修饰):基本数据类型的包装类、String & StringBuilder & StringBuffer、

  常用可继承的类:集合类

  继承了Comparable<Integer>,可以进行比较

 

 3.2 分析

 

参考

 

 

未完待续

 

posted @ 2019-12-03 17:32  YangDanMua  阅读(278)  评论(0编辑  收藏  举报