分享

最新分享

 zhuoyue图书馆 2011-09-28
Java自动装箱与自动拆箱

弄清楚了关于String的比较之后,昨天突发奇想地冒出一些问题。

Java里面的每个基本类型(primitive type)都有对应的引用类型(包装类wrapper),哈,问题就是与这个有关滴~

打开eclipse写了个Integer i=1; 没有报错(呃,俺不了解autoboxing...)。然后又陆续写了一些乱七八糟的,出现了一些意外的结果。纠结了很久,想起autoboxing,有的问题想清楚了有的还没有;回寝室的路上又想起autounboxing,今天上网查了查相关资料,算是弄明白了。

开始写的是:
public class EqualsDemo
{
    public static void main(String[] args) {
        int i1=1,i2=1;
        Integer iv1=1,iv2=1;  
        Integer in1=new Integer(1),in2= new Integer(1);
  
        print("(1) " + (i1==i2)); //(1)
        print("(2) " + (iv1==iv2)); //(2)
        print("(3) " + (in1==in2)); //(3)
        print("(4) " + (i1==iv1)); //(4)
        print("(5) " + (i1==in1)); //(5)
        print("(6) " + (iv1==in1)); //(6)
    }
    static void print(Object obj){
        System.out.println(obj);
    }
}

输出结果:
(1) true
(2) true
(3) false
(4) true
(5) true
(6) false

(1) true:明白,==比较基本类型的值,i1、i2都是int类型,值相等。
(2) true:迷茫了。iv1、iv2是引用类型啊,这两个引用为什么会相等?这里没有显式地使用new,iv1和iv2到底是不是堆上的对象?如果是就不可能相等。如果不是,那它们存储在什么位置?
(3) false:明白,两个用new创建的在堆上的对象嘛。
(4) true:这个结果和(2)的结果让我totally confused. 一个引用类型和一个基本类型比较?比较的是什么?
(5) true:。。。
(6) false:两个引用类型比较。

总结了一下,我不明白的问题:
1、Integer这样的包装类的变量为什么可以直接赋值?
2、一个基本类型和其封装类型比较[参看(4)(5)]为什么会有诡异的结果?
3、i1==iv1,i1==in1的结果是真,为什么iv1==in1的结果就是假了呢?

是的是的是的!这一切的问题归结为autoboxing和autounboxing!!!

autoboxing和autounboxing是java5开始引入了机制,方便了基本类型和其对应的wrapper类型的转换。

autoboxing:可以直接把一个基本类型的值赋给其wrapper类型(所以Integer i=1;这样就不会有错了~),也可以把一个基本类型直接放入容器里(java5之前基本类型是不能放进容器中的),封装的过程由编译器来完成。

autounboxing:可以直接用wrapper类型变量给基本类型变量赋值,总之就是和autoboxing相反的过程,也是由编译器来完成的。

编译器是怎么完全封箱和拆箱的呢?
Integer i=1; 相当于 Integer i=Integer.valueOf(1);
valueOf(int):返回一个表示指定的int值的Integer实例。如果不需要新的Integer实例,则通常应优先使用该方法,而不是构造方法 Integer(int),因为该方法有可能通过缓存经常请求的值而显著提高空间和时间性能。[jdk api文档]
是的,缓存是关键,这能解释为什么(2)的结果是true。

Byte,Integer 和Long都是缓存了-128~+127之间的对象,autoboxing的时候,如果需要boxing的值在此范围之内,则直接返回缓存的对象,没有的时候再去new.

Boolean类型中直接缓存了两个Boolean对象,true和false,这样使用valueOf()方法时只需要直接返回这两个对象中的一个,而不是每次调用的时候都用new,这也就是文档里所说的通过缓存经常请求的值二显著提高空间和时间性能。

Character因为类型的特殊性,保存的是0-127之间的对象。

自动装箱不是直接调用new来完成的,要不然(2)应该是false。

拆箱则是调用了wrapper类的xxxValueOf()方法,所以记住此时不允许wrapper类的对象为null。

所以到这里就把(2)弄明白了。如果把所有的值都改成1000,输出的结果是:
(1) true
(2) false
(3) false
(4) true
(5) true
(6) false

发现(2)不再是true,这是因为Integer没有缓存1000这个值。(关于缓存,我应该看看享元模式,曾经看过,没弄懂...)

(4)的结果永远是true,我觉得是发生了autounboxing,变成了两个基本类型的比较,(5)同理。(6)是两个引用类型比较,没有发生autoboxing。

由于autoboxing和autounboxing的存在,会有一些奇怪的现象...
比如把(6)中的"=="改成"<="或">=",输出的结果就会是true,因为发生了autounboxing。
另外,(in1!=in2)&&(in1<=in2)&&(in1>=in2) 结果会是ture,同样是因为autounboxing。

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多