Kotlin 的装箱操作

2019-03-24  本文已影响0人  JinYx

  在看Kotlin的基本类型时,文档提到,Kotlin中所有东西都是对象;并且数字在 Java 平台是物理存储为 JVM 的原生类型,除非我们需要一个可空的引用(如 Int?)或泛型。 后者情况下会把数字装箱。
   刚看到数字装箱,猜测是不是类似Java中基本类型的包装类,int —> Integer... 然后例子中又提到一个数字装箱不一定保留同一性,判断的是两个数值的引用地址。如果是按照 Integer来装箱,boxedA 和 anotherBoxedA 应该是两个不同的 Integer对象,引用一定不同。


图1. Kotlin装箱不一定保留同一性

   实践出真知,上代码

    fun testPacking() {
        val a: Int = 10000
        println(a === a) // 输出“true”
        val boxedA: Int? = a
        val anotherBoxedA: Int? = a
        println(boxedA === anotherBoxedA) // !!!输出“false”!!!
    }

    fun testPacking2() {
        val a: Int = 100
        println(a === a) // 输出“true”
        val boxedA: Int? = a
        val anotherBoxedA: Int? = a
        println(boxedA === anotherBoxedA) // !!!输出“true”!!!
    }

   上面的代码中,a的值不同,造成的结果也不同;查看一下Kotlin编译出的Java字节码,选中IDEA上面菜单栏的 Tools —> Kotlin —> Show Kotlin Bytecode,在打开的Kotlin Bytecode窗口中点击 Decompile


图2. 查看Kotlin Bytecode

  上面代码编译成字节码后,对应的代码如下

   public final void testPacking() {
      int a = 10000;
      boolean var2 = true;
      System.out.println(var2);
      Integer boxedA = Integer.valueOf(a);
      Integer anotherBoxedA = Integer.valueOf(a);
      boolean var4 = boxedA == anotherBoxedA;
      System.out.println(var4);
   }

   public final void testPacking2() {
      int a = 100;
      boolean var2 = true;
      System.out.println(var2);
      Integer boxedA = Integer.valueOf(a);
      Integer anotherBoxedA = Integer.valueOf(a);
      boolean var4 = boxedA == anotherBoxedA;
      System.out.println(var4);
   }

  果不其然,是通过 Integer 将数字进行了装箱操作,但是两个数值得到的值确实不一样的,查看Integer.valueOf()的源码:

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

发现i的值在-128到127之间时,是从IntegerCache.cache中拿的,而不在该范围则是每次创建一个Integer对象

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;
            // 省略部分代码......
            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;
        }

        private IntegerCache() {}
    }

所以Kotlin文档的示例代码中说的不一定保留同一性,表示的是数字范围在[-128, 127],引用相同,其他不同

上一篇下一篇

猜你喜欢

热点阅读