先看以下两段代码:
代码片段1:
- Integer i1 =100;
- Integer i2 =100;
- // Operator ==
- if(i1 == i2){
- System.out.println("i1 == i2 ");
- } else{
- System.out.println("i1 != i2");
- }
- // method equals()
- if(i1.equals(i2)){
- System.out.println("i1 == i2 ");
- }else{
- System.out.println("i1 != i2 ");
- }
- //执行结果如下
- i1 == i2
- i1 == i2
代码片段2:
- Integer i1 =200;
- Integer i2 =200;
- // Operator ==
- if(i1 == i2){
- System.out.println("i1 == i2 ");
- } else{
- System.out.println("i1 != i2");
- }
- // method equals()
- if(i1.equals(i2)){
- System.out.println("i1 == i2 ");
- }else{
- System.out.println("i1 != i2 ");
- }
- //执行结果是:
- i1!=i2
- 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创建该数据类型实例时,传入该数据类型即可。
例如:
- Integer data = 10;
- Integer wrapper = new Integer(data);
- System.out.println(data/3); //基本数据运算 输出 3
- System.out.println(wrap.doubleValue()/3); //操作Integer中的相关方法 输出 3.3333333
于是乎,wrapper就是一个整型的对象,便可以使用Integer类中的方法,静态变量,常量等丰富的资源。而data就不能使用,只有眼巴巴的份。
从JavaSE5.0开始,自动装箱(翻译为Auto Boxing)和自动拆箱(Auto unboxing)的出现,让上面的操作变得简单起来,这是“编译程序蜜糖”的功劳。从这个角度来看,每一个技术牛人都是一个长不大且爱玩的小朋友,因为总想吃糖。
二,自动装箱(Auto Boxing):
装箱,其实质还是打包数据类型,如上面的例子可以改写为:
- Integer wrapper = 10;
就是这么简单,再例如更一般化的Number类来自动装箱:
- Number number = 100L;
【100L会先被自动装箱为Long,然后指定给number】
其他类型亦是如此。
三,自动拆箱(Auto unboxing):
拆箱,顾名思义,就是自动取出打包器中的基本形态信息。
例如:
- Boolean yes = true;
- System.out.println(yes && false);//输出结果是false.
四,自动装箱与拆箱的实质
如例子:
- Float f = 3.14f; //不错,我举的例子就是圆周率。
在oracle/Sun 的JDK上,编译程序蜜糖,我现在特别喜欢这个词语,会自动将程序代码展开为:
- Float f = Float.valueOf(3.14f);
翻了翻JDK7的API文档发现,valueOf()函数在八大基本类中是那么的受欢迎,无异于眼下莫言的《丰富肥臀》在各大图书市场的火爆。
事实上,下面的这个例子也是合情合理的,但是执行呢?
- Float f1 = null;
- float f2 = f1;
蜜糖给出的解释是:
- Float float = null;//类类型默认值为null,一种特殊的数据类型
- float f1 = float.floatValue();
这段代码在编译的时候是通过的,但是执行的时候就会报出一个NullPointerException的错误。就相当于莫言童鞋将除了《丰乳肥臀》之外的3本书送给了甲乙丙,他却问甲乙丙有《丰乳肥臀》.
五,回归
分析equals()方法,因为i1,i2均为对象,且只想同样的一个数值,所以使用equals()的两个判断语句执行结果都是一样的。
为什么使用操作符 == 的时候却出现了变化了呢?
翻出JDK7安装目录下的src.zip文档,当然我是借助于IDE读取的,找到了Integer.valueOf()的定义,如下:
- public static Integer valueOf(int i) {
- assert IntegerCache.high >= 127;
- if (i >= IntegerCache.low && i <= IntegerCache.high)
- return IntegerCache.cache[i + (-IntegerCache.low)];
- return new Integer(i);
- }
i的范围是【-128,127】,而200不在这范围内,根据判断条件,返回的是一个新的Integer对象,因此在使用操作符 == 的时候,便出现了“i1!=i2”的结果。
其他类型的valueOf()有自己的定义,需要在查看之.
六,后续
编译程序蜜糖的事情再举个例子,比如增强的for循环。
例如:
- //Integer[] array = {new Integer(89),new Integer(99),new Integer(109)};//普通写法
- Integer[] array ={89,99,109}; //蜜糖写法
- //增强的for循环
- for(int arr :array){
- System.out.printf(“%2d”,arr);
- }
- //普通for循环
- for(int i=0;i<array.length;i++){
- System.out.printf(“%2d”,arr[i]);
- }
- //虽然输出的结果是一样的,代码量相对来说省了不少,真甜。