转载于 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参数才起作用。

 

Integer 与 int -- 自动装箱(autoboxing)与自动拆箱(unboxing)的更多相关文章

  1. 【C#】 装箱 (boxing) 和拆箱 (unboxing)

    目录: 1. 装箱和拆箱 2. 深入理解装箱和拆箱 3. int[] to object[],值类型数组到对象数组的转化 4. 使用泛型减少装箱和拆箱 1.  装箱和拆箱 装箱 就是把“值类型”转换成 ...

  2. C#中的装箱(inboxing)和拆箱(unboxing)(简单理解)

    装箱和拆箱是值类型和引用类型之间相互转换是要执行的操作.  装箱:将一个值类型隐式地转换成一个object类型,或把这个值类型转换成一个被该值类型应用的接口类型,把一个值类型的值装箱,就是创建一个ob ...

  3. int和Integer的自动拆箱/装箱相关问题

    java中为没一种基本类型都提供相应的包装类型. byte,short,char,int,long,float,double和boolean Byte,Short,Character,Integer, ...

  4. Java连载77-Integer常用方法、Integer、int、String三者相互转化、自动装箱、自动拆箱

    一.关于Integer中常用的方法 package com.bjpowernode.java_learning; ​ public class D77_1_ { public static void ...

  5. Java 自动装箱与拆箱(Autoboxing and unboxing)

    什么是自动装箱拆箱 基本数据类型的自动装箱(autoboxing).拆箱(unboxing)是自J2SE 5.0开始提供的功能. 一般我们要创建一个类的对象实例的时候,我们会这样: Class a = ...

  6. Java 性能要点:自动装箱/ 拆箱 (Autoboxing / Unboxing)

    [编者按]本文作者为 Ali Kemal TASCI,最早于2016年4月9日发布于DZONE社区.文章主要介绍通过改进 Java 1.5 就已存在的骨灰级特性大幅度提高应用性能. 本文系 OneAP ...

  7. Java 自动装箱与拆箱(Autoboxing and unboxing)

    什么是自动装箱拆箱 基本数据类型的自动装箱(autoboxing).拆箱(unboxing)是自J2SE 5.0开始提供的功能. 一般我们要创建一个类的对象实例的时候,我们会这样: Class a = ...

  8. 转:Java 自动装箱与拆箱(Autoboxing and unboxing)

    转: http://www.cnblogs.com/danne823/archive/2011/04/22/2025332.html 什么是自动装箱拆箱 基本数据类型的自动装箱(autoboxing) ...

  9. 自动装箱拆箱(Autoboxing,Unboxing)

    自动装箱和拆箱 https://docs.oracle.com/javase/tutorial/java/data/autoboxing.html 1.5才有(Autoboxing,Unboxing) ...

  10. Java暗箱操作之自动装箱与拆箱

    我以前在写Android项目的时候,估计写得最多最熟练的几句话就是: List<Integer> list = new ArrayList<Integer>(); list.a ...

随机推荐

  1. 个人介绍&我的GitHub注册经历&初步使用

    (1)个人介绍 我叫刘雨恬,目前是南通大学计科院网络工程141班的一名大二的学生,学号1413042004.由于学习软件工程的需要,我注册了cnblogs的这个博客账号,方便以后的学习交流.在兴趣爱好 ...

  2. 国际时区 TimeZone ID列表

    public static void main(String[] args) { Calendar c = new GregorianCalendar(); c.setTime(new Date()) ...

  3. svn: Can't convert string from 'UTF-8' to native encoding: 解决办法

    在linux中,svn co 或 svn up 时有中文文件名的文件的话,可能会报下面的错: [root@linkea-dev-srv1 ~]# svn upsvn: Can't convert st ...

  4. ASP.NET添加Mysql数据源

    在ASP.NET的数据源控件上添加mysql数据库连接,首先需要在windows系统下添加mysql的数据源才能在vs中添加数据源 1.在控制面板下打开系统与安全-->打开管理工具-->点 ...

  5. dockerfile构建redis

    -------------------------------------------------------------

  6. [JXOI2017]颜色 线段树求点对贡献

    [JXOI2017]颜色 题目链接 https://www.luogu.org/problemnew/show/P4065 题目描述 可怜有一个长度为 n 的正整数序列 Ai,其中相同的正整数代表着相 ...

  7. GO学习笔记 - 包内首字母大写的名称是被导出的,才能被其它包代码调用!

    在GO语言的任意包内,如果名称的首字母是大写的,意味着这个名称被导出,在其它包中可以使用“包名.名称”方式来调用,如果名称首字母不是大写,那么只能在这个包内部使用!这个概念还真是和以往接触的编程语言的 ...

  8. fd - 更好的 find 命令

    欢迎关注我的公众号 spider-learn fd(https://github.com/sharkdp/fd) 是 find 命令的一个更现代的替换. 对比一下 查找名字含有某个字符的文件 OLD ...

  9. javascript获取网址参数

    通过以上图片,就可以很好的理解: location.href location.protocol location.host location.hostname location.port locat ...

  10. React 组件模式

    简评:组件(component)是 React 的核心,了解它们有助于构建好的设计结构. 什么是组件(component) 组件运行你将 UI 拆分为独立的可重用的部分.和 JavaScript 函数 ...