从原理剖析自动拆装箱

前言:自动拆装箱是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 {

    // 自动拆箱
	@Test
	public void method1() {
		Integer i = new Integer(100);
		int a = i;
	}
	
	// 自动装箱
	@Test
	public 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 {

	@Test
	public 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 一个新对象。

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


  • 7
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值