Java自学笔记系列二:基本数据类型的装箱与拆箱

 

先看以下两段代码:

代码片段1:

 

  
  
  
  
  1. Integer i1 =100
  2. Integer i2 =100
  3. // Operator ==  
  4. if(i1 == i2){ 
  5.     System.out.println("i1 == i2 "); 
  6.  } else
  7.     System.out.println("i1 != i2"); 
  8.  } 
  9. // method equals() 
  10. if(i1.equals(i2)){ 
  11.     System.out.println("i1 == i2 "); 
  12.  }else
  13.     System.out.println("i1 != i2 "); 
  14. //执行结果如下 
  15. i1 == i2 
  16. i1 == i2 

代码片段2:

  
  
  
  
  1. Integer i1 =200
  2. Integer i2 =200
  3. // Operator ==  
  4. if(i1 == i2){ 
  5.     System.out.println("i1 == i2 "); 
  6. else
  7.     System.out.println("i1 != i2"); 
  8. // method equals() 
  9. if(i1.equals(i2)){ 
  10.     System.out.println("i1 == i2 "); 
  11. }else
  12.     System.out.println("i1 != i2 "); 
  13.              //执行结果是: 
  14.              i1!=i2 
  15.              i1==i2 

 比较看出,仅仅修改了一个数字,结果却有所不同,这到底是为什么呢?

  究其原因,原来是编译程序蜜糖(compiler sugar)给你带来的甜头。【顾名思义,我们写少且对的代码,编译器多劳动点】

先说下以下几个概念:

一,打包(Wrapper)

  不错,java和C++中都有包(package)的概念,java中还有jar包的存在,但是此包非彼包,但是都是从同一个形象的角度说明的。


话说在 JavaSE 5.0 之前,java的八大基本数据类型:long,int,double,float,boolean,short,char,byte必须亲自使用Long,Integer,Double,Float,Boolean,Short,Character,Byte类打包为对象,才能当做对象使用。又被称之为打包器。

 上述八大基本类型打包器都位于java.lang包之中。故若使用哪种数据类型,方式之一就是用new创建该数据类型实例时,传入该数据类型即可。

  例如:

  
  
  
  
  1. Integer data = 10
  2. Integer wrapper = new Integer(data); 
  3. System.out.println(data/3); //基本数据运算 输出 3 
  4. System.out.println(wrap.doubleValue()/3); //操作Integer中的相关方法 输出 3.3333333 

于是乎,wrapper就是一个整型的对象,便可以使用Integer类中的方法,静态变量,常量等丰富的资源。而data就不能使用,只有眼巴巴的份。

   从JavaSE5.0开始,自动装箱(翻译为Auto Boxing)和自动拆箱(Auto unboxing)的出现,让上面的操作变得简单起来,这是“编译程序蜜糖”的功劳。从这个角度来看,每一个技术牛人都是一个长不大且爱玩的小朋友,因为总想吃糖。

二,自动装箱(Auto Boxing):

 
  装箱,其实质还是打包数据类型,如上面的例子可以改写为:

  
  
  
  
  1. Integer wrapper = 10

  就是这么简单,再例如更一般化的Number类来自动装箱:

  
  
  
  
  1. Number number = 100L; 


【100L会先被自动装箱为Long,然后指定给number】

其他类型亦是如此。

三,自动拆箱(Auto unboxing):

  拆箱,顾名思义,就是自动取出打包器中的基本形态信息。
  例如:

  
  
  
  
  1. Boolean   yes  = true
  2. System.out.println(yes && false);//输出结果是false. 

四,自动装箱与拆箱的实质

   如例子:

  
  
  
  
  1. Float f = 3.14f; //不错,我举的例子就是圆周率。 

  在oracle/Sun 的JDK上,编译程序蜜糖,我现在特别喜欢这个词语,会自动将程序代码展开为:

  
  
  
  
  1. Float f = Float.valueOf(3.14f); 

   翻了翻JDK7的API文档发现,valueOf()函数在八大基本类中是那么的受欢迎,无异于眼下莫言的《丰富肥臀》在各大图书市场的火爆。
  

  事实上,下面的这个例子也是合情合理的,但是执行呢?

  
  
  
  
  1. Float f1 = null
  2. float f2 = f1; 

  蜜糖给出的解释是:

  
  
  
  
  1. Float float = null;//类类型默认值为null,一种特殊的数据类型 
  2. float f1 = float.floatValue(); 

   这段代码在编译的时候是通过的,但是执行的时候就会报出一个NullPointerException的错误。就相当于莫言童鞋将除了《丰乳肥臀》之外的3本书送给了甲乙丙,他却问甲乙丙有《丰乳肥臀》.

五,回归

  分析equals()方法,因为i1,i2均为对象,且只想同样的一个数值,所以使用equals()的两个判断语句执行结果都是一样的。

  为什么使用操作符 == 的时候却出现了变化了呢?

  翻出JDK7安装目录下的src.zip文档,当然我是借助于IDE读取的,找到了Integer.valueOf()的定义,如下:

  
  
  
  
  1. public static Integer valueOf(int i) { 
  2.        assert IntegerCache.high >= 127
  3.        if (i >= IntegerCache.low && i <= IntegerCache.high) 
  4.            return IntegerCache.cache[i + (-IntegerCache.low)]; 
  5.        return new Integer(i); 
  6.    } 

 i的范围是【-128,127】,而200不在这范围内,根据判断条件,返回的是一个新的Integer对象,因此在使用操作符 == 的时候,便出现了“i1!=i2”的结果。

   其他类型的valueOf()有自己的定义,需要在查看之.

六,后续

   编译程序蜜糖的事情再举个例子,比如增强的for循环。

   例如:  

  
  
  
  
  1. //Integer[] array = {new Integer(89),new Integer(99),new Integer(109)};//普通写法 
  2. Integer[] array ={89,99,109};   //蜜糖写法
  3. //增强的for循环 
  4. for(int arr :array){ 
  5.    System.out.printf(“%2d”,arr); 
  6. //普通for循环 
  7. for(int i=0;i<array.length;i++){ 
  8.    System.out.printf(“%2d”,arr[i]); 
  9. //虽然输出的结果是一样的,代码量相对来说省了不少,真甜。 

 

你可能感兴趣的:(java,自动装箱,自动拆箱,编译程序蜜糖)