• Integer 与 int -- 自动装箱(autoboxing)与自动拆箱(unboxing)


    转载于 http://www.ticmy.com/?p=110

    jdk1.5引入了自动装箱(autoboxing)与自动拆箱(unboxing),这方便了集合类以及一些方法的调用,同时也使初学者对其感到非常之困惑。在此,我们来揭开其神秘的面纱。

    首先,需要厘清一些概念:
    1、Integer是一个类,用Integer声明一个变量其是一个对象类型(或者说引用类型);int是基本类型,用int声明的变量是非对象类型,即不能在其上调用方法。
    2、“==”作用于对象上的时候,其比较的是对象的引用本身的值(或者说对象的地址更容易理解),而作用于基本类型的时候比较的就是基本类型的值。

    接下来看一段代码:

    public class Test {
        publicstatic void main(String[] args) {
            Integer i1 =2;
            int i2 = 2;
            System.out.println(i1 == i2);
        }
    }

    在这段代码中有两个令人困惑的问题,首先是将一个基本类型的值赋值给对象的引用,即Integer i1 =2;其次是拿一个对象类型和一个基本类型比较。按理说这两种做法肯定都是有问题的,在jdk1.4(若使用的jdk版本是1.5或之后的版本中,可以使用javac -source 1.4 Test.Java来编译)上,确实如此,第一个问题在编译时会报“不兼容的类型”错误,第二个问题会报“运算符 == 不能应用于 java.lang.Integer,int”的错误。

    但是jdk1.5引入的自动装箱和自动拆箱,那么,必然要将其中的一种类型转换成另一种类型,究竟是将Integer对象i1转换成int基本类型呢?还是将int基本类型的i2转换成Integer对象?通过javap -c Test反编译Test.class文件就知道答案了:

    public static void main(java.lang.String[]);
      Code:
       0:   iconst_2
       1:   invokestatic    #2;//Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
       4:   astore_1
       5:   iconst_2
       6:   istore_2
       7:   getstatic       #3;//Field java/lang/System.out:Ljava/io/PrintStream;
       10:  aload_1
       11:  invokevirtual   #4;//Method java/lang/Integer.intValue:()I
       14:  iload_2
       15:  if_icmpne      22
       18:  iconst_1
       19goto    23
       22:  iconst_0
       23:  invokevirtual   #5;//Method java/io/PrintStream.println:(Z)V
       26return
    }

    其中,[0-4]是Integer i1 = 2的实现,我们发现,编译的字节码里调用了Integer.valueOf方法,因此Integer i1 = 2编译后就等同于Integer i1 = Integer.valueOf(2);[5,6]是int i2 = 2的实现;[7,23]是System.out.println(i1 == i2)的实现,也容易看到,里面调用了Integer.intValue()方法。因此,这个i1 == i2这两个不同类型的变量比较,在编译的时候,编译器是将其转换成相同的类型进行比较的,即将对象类型转换成基本类型,System.out.println(i1 == i2)就等同于System.out.println(i1.intValue() == i2),前面说了,“==”作用于基本类型的时候比较的就是基本类型的值,两个值都是2,所以结果是true。

    另外一个令人困惑的例子就是:

    public class Test {
        publicstatic void main(String[] args) {
            Integer i1 =127;
            Integer i2 =127;
            System.out.println(i1 == i2);
     
            Integer i3 =128;
            Integer i4 =128;
            System.out.println(i3 == i4);
        }
    }

    运行后发现,i1==i2的结果为true,i3==i4的结果为false?这令不知原因的人头疼不已。在前面一个例子里我们已经说过,诸如Integer i1 = 127,在编译后就等同于Integer i1 = Integer.valueOf(127),既然是调用一个方法来获得对象,那么就有必要对valueOf方法一探究竟了。我们看下源码:

    public static Integer valueOf(inti) {
        finalint offset = 128;
        if(i >= -128 && i <= 127) { // must cache
            returnIntegerCache.cache[i + offset];
        }
        returnnew Integer(i);
    }

    到此应该恍然大悟了,IntegerCache缓存了[-128,127]之间的Integer对象,如果valueOf的参数i处于这之间,就返回缓存的对象。否则就new一个新的Integer。前面已经说过,“==”作用于对象上的时候,其比较的是对象的地址,例子中的i1和i2都是从缓存中拿的,当然是同一个对象,i3和i4都是通过new Integer获得的,当然不是同一个对象了。

    类似地,java.lang.Long,java.lang.Short分别缓存了[-128,127]之间的Long和Short对象,java.lang.Byte缓存了所有的对象,java.lang.Character缓存了[0,127]之间的Character对象。java缓存这些对象是为了性能优化,既然我们已经知道其缓存了这么些对象,在需要new Integer/Long/…的地方,可改用Integer/Long/Short…#valueOf方法。


    但是:

    使用Oracle/Sun JDK 6,在server模式下,使用-XX:AutoBoxCacheMax=NNN参数即可将Integer的自动缓存区间设置为[-128,NNN]。注意区间的下界固定在-128不可配置。
    在client模式下该参数无效。这个参数是server模式专有的,在c2_globals.hpp中声明,默认值是128;不过这个默认值在默认条件下不起作用,要手动设置它的值或者是开启-XX:+AggressiveOpts参数才起作用。

     
  • 相关阅读:
    vue computed watch 使用区别
    element 问题
    vue vue.config.js
    vue 路由
    算法
    《概率统计》10.变与不变:马尔科夫链的极限与稳态
    《概率统计》9.状态转移:初识马尔科夫链
    《概率统计》8.由静向动:随机过程导引
    《概率统计》7.统计推断:寻找最大似然与最大后验
    《概率统计》6.推断未知:统计推断的基本框架
  • 原文地址:https://www.cnblogs.com/wihainan/p/5960408.html
Copyright © 2020-2023  润新知