从原理剖析自动拆装箱

来源:互联网 发布:淘宝口红代购 编辑:程序博客网 时间:2024/06/05 21:08

前言:自动拆装箱是JDK1.5的新特性,这一特性使得基本类型与对应的包装器类型(引用类型)之间能够直接进行互相转换,例如将int类型与Integer类型,我们可以将int类型当做Integer类型来使用。非常方便,但是这样也隐藏了许多细节,那么这些细节是什么,相互转换的原理是什么呢?

1、什么是自动拆装箱?

  定义:能够使基本类型与其对应的包装器类型之间自动相互转换。对应关系如下:

<span style="font-size:14px;">  byte <--> Byte  short <--> Short  int <--> Integer  long <--> Long  float <--> Float  double <--> Double  boolean <--> Boolean  char <--> Character </span>
2、自动拆装箱原理?

  需要注意的是,自动拆装箱不是虚拟机完成的,这个过程实际上是由编译器完成的,当编译器对 .java 源代码进行编译时,如果发现你没有进行拆箱,那么编译器来来帮你拆;如果你没有装箱,那么编译器来帮你装,而不是由虚拟机完成的。这个原理我们可以对代码进行反编译来解释,如下。

3、自动拆装箱举例与反编译。

  还是以int 和Integer 类型来举例,.java源代码编写如下:

<span style="font-size:14px;">public class Demo1 {    // 自动拆箱@Testpublic void method1() {Integer i = new Integer(100);int a = i;}// 自动装箱@Testpublic void method2() {Integer i = 100;}}</span>

  对代码进行反编译(编译后的字节码文件才是被虚拟机所执行的,对字节码文件进行反编译就是得到我们能看懂的虚拟机真正执行的内容),得到反编译文件内容为:

<span style="font-size:14px;">public class Demo1{  @Test  public void method1()  {    Integer i = new Integer(100);    int a = i.intValue();  }  @Test  public void method2()  {    Integer i = Integer.valueOf(100);  }}</span>
  发现:自动拆箱底层实际是用了Integer 对象的“.intValue()”方法,此方法返回一个int 类型的值;自动装箱实际是用了Integer 类的“.valueOf()” 方法,此方法返回一个Integer类型对象。

4、一个非常容易犯错的题目。

  猜打印出的布尔值:

<span style="font-size:14px;">public class Demo2 {@Testpublic void method() {Integer i1 = 100;Integer i2 = 100;Integer i3 = 200;Integer i4 = 200;System.out.println(i1 == i2); System.out.println(i3 == i4);}}</span>
  答案:第一个为true;第二个为false。

  “==”用于比较值,在这里比较的是引用类型的地址值,如果相等,说明被比较的两个对象的引用指向同一个对象;否则指向不同的对象。那为什么一个相同,一个不同呢?

  首先来看一个反编译代码:

<span style="font-size:14px;">public class Demo2{   @Test  public void method()  {    Integer i1 = Integer.valueOf(100);    Integer i2 = Integer.valueOf(100);    Integer i3 = Integer.valueOf(200);    Integer i4 = Integer.valueOf(200);    System.out.println(i1 == i2);    System.out.println(i3 == i4);  }}</span>
  可以看到,装箱过程都是用的valueof方法,所以得出不同结果的原因都在valueof方法上,让我们来看一下java 底层valueof 方法,如下:

<span style="font-size:14px;">      public static Integer valueOf(int i) {final int offset = 128;if (i >= -128 && i <= 127) { // must cache     return IntegerCache.cache[i + offset];}        return new Integer(i);    } </span>
  发现:只要是valueof()方法传入的参数介于-128 和 127 之间,都不会创建对象;而对于这个范围以外的int类型数字,都会创建对象。发现,这和单例模式中的懒汉式模式十分相似。

  说明:当 Integer 类一旦被加载,就会在内部缓存(创建)-128~127之间的256个 Integer 对象,如果 valueOf(int i) 方法需要把这个范围之内的整数转换成Integer对象时,valueOf(int i)方法不会去new对象,而是从缓存中直接获取同一个 Integer 对象!如果 valueOf(int i) 方法收到的参数不在缓存范围之内,那么 valueOfint i) 方法会 new 一个新对象。

  小结:自动拆装箱方便了程序的编写,但是在方便的同时,也为我们隐藏了一些细节,要想了解这些细节,就需要对源代码进行探讨,希望大家也都不要满足于会使用即可,原理层次的东西还是要了解的。


3 0
原创粉丝点击