分享Java快乐

我有一份快乐,分给你一些;我还是有一份快乐,你也有一份快乐。

mxj ID:javamxj
517884次访问,排名75好友0人,关注者5
javamxj的文章
原创 82 篇
翻译 0 篇
转载 0 篇
评论 720 篇
javamxj的公告

    版权声明:在此发表的有关文章均属本人javamxj原创,转摘或引用请注明出处。



联系方式:
Email:
javamxj@gmail.com

友情Blog

最近评论
linuxghs:删除configuration,eclipse不能启动了。郁闷
xinghui100:学习中
IvonXiao:谢谢博主的分享
xkpkhu:wow power leveling
xkpkhu:wow power leveling
文章分类
收藏
    相册
    有空逛逛
    java开源大全(RSS)
    存档
    软件项目交易
    订阅我的博客
    XML聚合  FeedSky
    订阅到鲜果
    订阅到Google
    订阅到抓虾
    订阅到BlogLines
    订阅到Yahoo
    订阅到GouGou
    订阅到飞鸽
    订阅到Rojo
    订阅到newsgator
    订阅到netvibes

    原创 需要注意自动装拆箱的一个特例收藏

    新一篇: JavaScript 日志工具 | 旧一篇: 强烈推荐几个比较好的Java代码查询网站

    首先看一段代码(使用JDK 5),如下:
    public class Test {
      public static void main(String[] args) {
        Integer i1 = 127;
        Integer i2 = 127;
     
        if (i1 == i2)
          System.out.println("Equal!");
        else
          System.out.println("Not equal!");
      }
    }
     
        输出结果想必大家也知道,是“Equal!”。现在把i1和i2的值由127改为128看看会发生什么?结果输出“Not equal!”。
     
    提示:这段解释有错误,可以跳过看下面的。
           注意i1和i2都是Integer类型,事实上只要这个值的范围在“-128—127”之间,输出结果都是“Equal!”。JDK 5引进了很多新的特性,其中有一个就是自动装箱(Autoboxing)和自动拆箱(Auto-Unboxing)。当i1和i2值为128时,在进行“==”时,它们被装进两个不同的Integer Objects,由于这是两个不同的instances,它们引用不同的内存地址,所以结果是“Not equal!”。 但当这个值是127时,JVM自动将这个值转换成基本类型int,这样进行“==”时,JVM仍然使用的是相同的object instance, 所以输出结果为“Equal!”了。
        
        真是讨厌!

    修改后的:

    首先感谢abcdhy网友指出问题,为了更能鞭策自己,我会将上面错误的解释一直留着,时刻提醒自己,研究问题一定要脚踏实地,多方考证。
     
       
    为了方便说明问题,我写了下面的代码:
     
    public class Test {
      public static void main(String[] args) {
        Integer i1 = 127;
        Integer i2 = 127;
        Integer i3 = Integer.valueOf(127);
     
        if (i1 == i2)
          System.out.println("i1 == i2 is true!");
        else
          System.out.println("i1 == i2 is false!");
     
        if (i1 >= i2)
          System.out.println("i1 >= i2 is true!");
        else
          System.out.println("i1 >= i2 is false!");
     
        if (i1 == i3)
          System.out.println("i1 == i3 is true!");
        else
          System.out.println("i1 == i3 is false!");
     
      }
    }
    当值是127时,输出是:
    i1 == i2 is true!
    i1 >= i2 is true!
    i1 == i3 is true!
     
    当值是128时,输出是:
    i1 == i2 is false!
    i1 >= i2 is true!
    i1 == i3 is false!
     
    说明:
       我使用的是Sun JDK 1.5.0_03-b07 和 Eclipse 3.2M4。
      
       “Integer i1 = 127;”在JDK1.4下不能编译通过的,会提示:“ Type mismatch: cannot convert from int to Integer”的错误,一般改写为:“Integer i1 = new Integer(127);”。
       
       “Integer i1 = 127;”在JDK1.5下可以编译通过的,这就是自动装箱(Autoboxing)和自动拆箱(Auto-Unboxing)。自动装箱(Autoboxing)特性让Java自动包装一个简单数据类型(例如int)到对应的包装类型中(例如Integer)中。
     
        在《JSR 201: Extending the Java Programming Language with Enumerations, Autoboxing, Enhanced for loops and Static Import》中,对这个问题,是作了这样的规定:
        If the value p being boxed is true, false, a byte, an ASCII character, or an integer or short number between -127 and 128, then let r1 and r2 be the results of any two boxing conversions of p. It is always the case that r1 == r2.
     
        在Java中,The following is the list of primitives stored as immutable objects(不可变对象:
    * boolean values true and false
    * All byte values
    * short values between -128 and 127
    * int values between -128 and 127
    * char in the range \u0000 to \u007F
     
       为了更容易理解问题,用Jad将上面代码反编译,如下:
    import java.io.PrintStream;
     
    public class Test
    {
     
        public Test()
        {
        }
     
        public static void main(String args[])
        {
            Integer i1 = Integer.valueOf(128);
            Integer i2 = Integer.valueOf(128);
            Integer i3 = Integer.valueOf(128);

            if(i1 == i2)
                System.out.println("i1 == i2 is true!");
            else
                System.out.println("i1 == i2 is false!");

            if(i1.intValue() >= i2.intValue())
                System.out.println("i1 >= i2 is true!");
            else
                System.out.println("i1 >= i2 is false!");

            if(i1 == i3)
                System.out.println("i1 == i3 is true!");
            else
                System.out.println("i1 == i3 is false!");
        }
    }
    从这可以看出,“Integer i1 = 127;”在JDK1.5下应该编译成了“Integer i1 = Integer.valueOf(127);”。
     
     
    再看看java.lang.Integer中关于valueOf的源代码是怎样的:
      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);
      }
     
        可以看出,这个值在-128到127之间,会将其cached(缓存)起来,如果多次使用的话,会节省内存和改善性能;如果不在这个范围之内,则生成一个新的Integer Object instance,这样如果进行“==”时,由于是比较两个不同的Object references,故结果是false。事实上,这个特性从JDK 1.3就存在了(以前的我不清楚) 。
     
        确切的说,上面出现的问题实质并不是Autoboxing和Auto-Unboxing,应该是Integer类的valueOf(int i)方法,只是Autoboxing和Auto-Unboxing将这个问题掩盖了。

    发表于 @ 2006年01月07日 14:01:00|评论(loading...)|编辑

    新一篇: JavaScript 日志工具 | 旧一篇: 强烈推荐几个比较好的Java代码查询网站

    评论

    #jerryao 发表于2006-07-03 16:07:00  IP: 211.100.21.*
    TrackBack来自《integer 的使用(JDK1.5) 》

    integer 的使用(JDK1.5)
    #longaway 发表于2006-01-08 14:41:00  IP: 221.216.102.*

    头一回知道。

    谢了。
    #kwx 发表于2006-01-08 21:31:00  IP: 221.221.22.*
    呵,又长见识了!平时真没注意到!
    #abcdhy 发表于2006-01-11 22:44:00  IP: 210.22.10.*
    晕, 作者你完全搞错了!

    希望你多看看 Java 的基础知识。还是对 Java 了解不深啊!!哈哈!!

    不管什么时候 i1 == i2 都是使用的 object instance 来比较的, 你这个代码在 Java1.4 和 Java1.5 运行结果都是一样的!

    根本就没有你说的 自动装箱(Autoboxing)和自动拆箱(Auto-Unboxing)。

    但为什么会出现你所说的情况呢?
    你看看 Integer 的源代码就知道:
    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);
    }
    *******这里是内置的数据**********
    private static class IntegerCache {
    private IntegerCache(){}

    static final Integer cache[] = new Integer[-(-128) + 127 + 1];

    static {
    for(int i = 0; i < cache.length; i++)
    cache[i] = new Integer(i - 128);
    }
    }

    看到了吧!!!!!
    Java 为了性能,系统中已经默认创建出了 -128~127 的 Integer 数据,你在创建这个范围的数据时,系统就直接给你一个 “引用”
    所以 在 Integer 在 -128~127 之间时,相同的数值得到的都是同一个对象。 所以才会“相同”

    而 大于了 127 就是当时新创建的对象了, 当然“引用”是不相等的了,因为指向了不同的对象了嘛!!!!!


    我这样说明白了吗???
    建议以后遇到问题的时候多看看 Java 的类库源代码,就能找到原因了。
    #abcdhy 发表于2006-01-13 12:48:00  IP: 210.22.10.*
    在 1.4 中
    Integer i1 = 127; (这里使用了 自动装箱)
    要改成 Integer i1 = new Integer(127);
    #Anubis 发表于2006-01-13 08:16:00  IP: 222.33.36.*
    jdk142 eclipse 提示错误
    Type mismatch: cannot convert from int to Integer
    #Anubis 发表于2006-01-13 08:33:00  IP: 222.33.36.*
    jdk1.5 eclipse3.1 仍然提示这个错误
    手动一整果然是这样。至于到底哪位英雄说得对呢?我们拭目以待。
    #bmshl 发表于2006-01-13 10:52:00  IP: 211.100.10.*
    abcdhy说的没错,对象的"=="运算都是比较是否相同的object instance
    #abcdhy 发表于2006-01-14 00:56:00  IP: 210.22.10.*
    作者很细心啊,连 JSR 都去查找了。呵呵

    多多交流!
    #afa2006 发表于2006-01-17 23:11:00  IP: 220.188.129.*
    从前,在一个初春的早上,一个老汉干活累了,于是他就找了快大石头躺下来休息。阳光暖暖的洒在他的身上,他感到从未有过的惬意,他一次次的会心的微笑来感激上苍赐于的快乐。忽然,他感到自己不应该独自享受,其他人可能还不知道呢?于是他飞快的跑回了家,对他妻子说:晒太阳真的好舒服啊,我要去告诉村里的每个人,我还要去告诉国王.....

    分享阳光,分享JAVA快乐
    #tianjj 发表于2006-02-05 16:04:00  IP: 218.249.163.*
    楼主,最为关注 you's blog,为你加油!
    #Jimin 发表于2006-02-16 09:05:00  IP: 211.144.200.*
    向各位学习
    #xjspa 发表于2006-03-29 21:34:00  IP: 222.78.246.*
    学习,还是abcdhy厉害!!!
    #longaway 发表于2006-05-20 13:23:00  IP: 61.149.176.*
    又看了一遍。
    #hehe 发表于2006-05-21 13:53:00  IP: 218.29.150.*
    遇到问题的时候是应该看看Java 的类库源代码
    #xmlfans 发表于2006-06-22 11:57:00  IP: 222.209.94.*
    厉害啊。。。这也可以佩服
    #lck047 发表于2007-07-30 16:30:16  IP: 218.74.254.*
    如果用Integer i1 = new integer(127)
    而非Integer i1 =127
    那么不论i1的值取多少都不会相等。

    由此可见当使用Integer i1 =?这个语句时,范围在-128到127之间是直接引用的(Java 为了性能,系统中已经默认创建出了 -128~127 的 Integer 数),而超出这个范围它就需要从新NEW一个了
    而Integer i1 = new integer(?),是无论什么情况下都是NEW出一个对象的,也就是说不论i1的值是不是在-128~127 之间都不会相等。

    个人理解
    发表评论  


    当前用户设置只有注册用户才能发表评论。如果你没有登录,请点击登录
    Csdn Blog version 3.1a
    Copyright © javamxj