查了一下Api,valueOf(int i),返回的是i值的Integer对象,Integer.valueOf()基于减少对象的创建次数和节省内存的考虑,[-128,127]之间的数字会被缓存,当valueOf()方法传入的参数在这个范围之内,将直接返回缓存中的对象。
我们来看一下一个例子
public static void main(String[] args) {
Integer a=Integer.valueOf(1);
Integer b=Integer.valueOf(1);
int c=1;
Integer d=1;
long e=1L;
Integer f=Integer.valueOf(321);
Integer g=Integer.valueOf(321);
Long i=2L;
System.out.println(a==b); //1
System.out.println(a==c); //2
System.out.println(a==d); //3
System.out.println(a==e); //4
System.out.println(c==e); //5
System.out.println(f==g); //6
System.out.println(i==(a+b)); //7
System.out.println(i.equals(a+b)); //8
}
结果为:
true
true
true
true
true
false
true
false
我们来看1,a,b都是Integer的对象,由于Integer.valueOf()缓存[-128,127]之间的数,因为传入的参数一样,所以返回的对象是一样的。与//6,即可以得到结果
对于2,因为c是数值,进行的是数值比较,a会自动拆箱,进行比较,故结果是正确的
对于3,Integer d=1和Integer d=Integer.valueOf(1)的效果是一样的,所以返回了同一个对象
对于4,e为数值,故为数值比较,a先自动拆箱为int数值,再转化为long型与e进行比较
对于5,则为c转化为long型,与e进行比较
对于7,因为a+b是算术运算,故a+b是一个值,“==”运算在遇到算术运算时会自动拆箱,成为int型的值,再转型成long型,与i的自动拆箱进行比较
对于8,因为Long型的equals()方法不处理数据转型的关系,故比较是错误的。
下面的内容摘自《effective java》第49条:基本类型优先于装箱基本类型
我们知道Java有一个类型系统由两个部分组成,包括基本类型,例如int,double和boolean,和引用类型,如String和List,每个基本类型对应于一个引用类型,称作装箱基本类型。即装箱基本类型中对应于int,double和boolean的是Integer,Double和Boolean。
下面我们来看一个很有趣的例子:
public static void main(String[] args) {
// TODO Auto-generated method stub
Integer a=new Integer(1);
Integer b=new Integer(1);
System.out.println(a<b?-1:(a==b?0:1));
}
在上面的例子中,如果我们不注意的话,我们得到的结果就是0,但是运行之后我们得到的结果是1;
根据《effective java》书上的解释,首先先比较a < b,执行这个计算会使得a,b进行自动拆箱,变成基本类型(此时基本类型就只有值),第一个比较不正确,则进行第二个比较,对于“==”的比较,则比较他的同一性,即这是装箱基本类型(引用类型)的比较,即比较它们的同一性,如果a和b引用表示同一个int值的不同Integer实例,则这个比较操作返回的值是false,故上面的程序返回的是1。
对于基本类型和装箱基本类型的区别有三点:
一、基本只有值,而装箱基本类型具有与它们的值不同的同一性,换句话说,就是两个装箱基本类型可以具有相同的值而有不同的同一性。(还是很生涩,照我的理解是,虽然它们的值相同,但是a和b是两个不相同的对象,它们在创建时地址是不一样的)
二:基本类型只有功能完备的值,而每个装箱基本类型除了它有对应的基本类型的所有功能之外,还有个非功能值:null
三:基本类型通常比装箱基本类型更节省时间和空间
现在我们来看看反编译的结果
import java.io.PrintStream;
public class Autoboxing
{
public Autoboxing()
{
}
public static void main(String args[])
{
Integer a = new Integer(1);
Integer b = new Integer(1);
System.out.println(a.intValue() >= b.intValue() ? ((int) (a != b ? 1 : 0)) : -1);
}
}
从上面的结果可以看出,在编译时,系统先给类添加了一个无参构造器,我们着重看下输出的比较部分,
首先先对对象a和b进行同一性的比较,比较的结果为true,故结果返回1,再对a>=b进行比较,首先先对a和b进行自动拆箱,用到intValue()方法进行拆箱,此时a和b都是基本类型,故单纯比较它们值是相等的,比较的结果为true,故结果返回1。所以整个程序的返回的结果是1。
下面我们再来看看例子:
public static void main(String[] args) {
Integer a=1;
Integer b=1;
Integer c=Integer.valueOf(1);
Integer d=2;
Long e=2L;
System.out.println(a==b);
System.out.println(a==c);
System.out.println(b==c);
System.out.println(d==(a+b));
System.out.println(d.equals(a+b));
System.out.println(e.equals(d));
}
上面程序的结果为:
true
true
true
true
true
false
下面我们用反编译的程序解释上面的结果
public class Autoboxing2
{
public Autoboxing2()
{
}
public static void main(String args[])
{
Integer a = Integer.valueOf(1);
Integer b = Integer.valueOf(1);
Integer c = Integer.valueOf(1);
Integer d = Integer.valueOf(2);
Long e = Long.valueOf(2L);
System.out.println(a == b);
System.out.println(a == c);
System.out.println(b == c);
System.out.println(d.intValue() == a.intValue() + b.intValue());
System.out.println(d.equals(Integer.valueOf(a.intValue() + b.intValue())));
System.out.println(e.equals(d));
}
}
首先对a,b进行自动装箱,用到valueOf()方法,这个方法在上面已经介绍过,故我们知道a,b和c具有同一性,故前三个比较返回的是true。
对于第四个比较,a+b,则先对a和b用intValue()方法进行自动拆箱,相加得到2这个值,再用对象d和值2进行”==”比较,对象d再用intValue()方法进行自动拆箱,得到2这个值,故结果返回的是true。
第五个比较则是先对a和b用intValue()方法进行自动拆箱,相加得到2这个值,再进行自动装箱,变成与对象d具有同一性,故返回的是true。
第六个比较,两个对象为不同的对象,故用equals方法比较返回的是false。
总结:
1、反编译的代码用了Integer.intValue()和Integer.valueOf()方法进行自动拆箱和自动装箱
2、在范围[-128,127]内的数值,自动装箱方法Integer.valueOf()会缓存,当valueOf()方法传入的参数在这个范围之内,将直接返回缓存中的对象,基于减少创建对象的次数和节省内存的考虑
3、通过”==”比较两个自动装箱的Integer实例时,只要两者表示的数值相等,结果就是相等的,因此他们的同一性是相同的
4、通过equals来比较的时候,只要同类型(包括自动装箱和拆箱)代表的数值相同的,就是相等的