A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© LoveGG 中级黑马   /  2016-7-4 00:07  /  3700 人查看  /  16 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

5黑马币

12.png (12.17 KB, 下载次数: 35)

想要获得最佳者,请给出详细解答

想要获得最佳者,请给出详细解答

最佳答案

查看完整内容

其实只要你可以理解自动装箱的本质就知道答案了: Integer a = 1; 这句代码实际上会被编译为 Ingeger a = Integer.valueOf(1); 从 Integer.java 的源代码中我们可以看到 Integer.valueOf 的源代码: http://hg.openjdk.java.net/jdk8/jdk8/jdk/file/687fd7c7986d/src/share/classes/java/lang/Integer.java#l829 我们可以看到,这个函数首先会判断这个数字是否在 Cache 的范围内,如果在则直接返回缓存,不在才会 new 一个新的并 ...

16 个回复

倒序浏览
本帖最后由 cat73 于 2016-7-5 12:00 编辑

其实只要你可以理解自动装箱的本质就知道答案了:
Integer a = 1;
这句代码实际上会被编译为
Ingeger a = Integer.valueOf(1);

从 Integer.java 的源代码中我们可以看到 Integer.valueOf 的源代码:
http://hg.openjdk.java.net/jdk8/jdk8/jdk/file/687fd7c7986d/src/share/classes/java/lang/Integer.java#l829
  1.     public static Integer valueOf(int i) {
  2.         if (i >= IntegerCache.low && i <= IntegerCache.high)
  3.             return IntegerCache.cache[i + (-IntegerCache.low)];
  4.         return new Integer(i);
  5.     }
复制代码

我们可以看到,这个函数首先会判断这个数字是否在 Cache 的范围内,如果在则直接返回缓存,不在才会 new 一个新的并返回。

我们继续看 IntegerCache 的实现:
http://hg.openjdk.java.net/jdk8/jdk8/jdk/file/687fd7c7986d/src/share/classes/java/lang/Integer.java#l780
  1.     private static class IntegerCache {
  2.         static final int low = -128;
  3.         static final int high;
  4.         static final Integer cache[];

  5.         static {
  6.             // high value may be configured by property
  7.             int h = 127;
  8.             String integerCacheHighPropValue =
  9.                 sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
  10.             if (integerCacheHighPropValue != null) {
  11.                 try {
  12.                     int i = parseInt(integerCacheHighPropValue);
  13.                     i = Math.max(i, 127);
  14.                     // Maximum array size is Integer.MAX_VALUE
  15.                     h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
  16.                 } catch( NumberFormatException nfe) {
  17.                     // If the property cannot be parsed into an int, ignore it.
  18.                 }
  19.             }
  20.             high = h;

  21.             cache = new Integer[(high - low) + 1];
  22.             int j = low;
  23.             for(int k = 0; k < cache.length; k++)
  24.                 cache[k] = new Integer(j++);

  25.             // range [-128, 127] must be interned (JLS7 5.1.7)
  26.             assert IntegerCache.high >= 127;
  27.         }

  28.         private IntegerCache() {}
  29.     }
复制代码

可以看到,low 被限制死了是 -128,而 high 则可以动态设置,默认值为 127。

那么你的问题就有答案了,在默认情况下:
第一题 1000 > IntegerCache.high,所以会 new 一个新的 Integer,所以这是两个对象,a != b。
第二题 100 >= IntegerCache.log && 100 <= IntegerCache.high,所以会直接返回缓存中的,所以这两个其实是同一个对象,a == b。
第三题解答有误,请看后面的楼层第三题 a 直接 new 了一个对象,b 实际上也是 new 了一个新的,所以这是两个对象,a != b。
第四题 a 与 b 都是直接 new 了一个新对象,所以这是两个对象,a != b。

而 IntegerCache.high 其实是可以设置的,你可以通过在启动参数中增加 -XX:AutoBoxCacheMax=1000 来让第一题的 a 与 b 是同一个对象。
第四题因为两个对象都没有通过 valueOf,所以无论怎么设置这个参数,这两道题里 a 都不等于 b。
你还可以设置 -XX:AutoBoxCacheMax=99,也就是一个小于 100 的数,让第二题里的 a != b。
回复 使用道具 举报
首先,这个问题的前提是Integer类型会自动装箱和自动拆箱.并且在-128到127的范围内,自动装箱不会创建新的对象,而是从常量池中获取.
二.==号比较引用数据类型时,比较的是地址值.
第一题:Integer a = 1000; Integer b = 1000;
a和b分别在堆内存中开辟一个新的地址值.所以结果为false.
第二题:Integer a = 100; Integer b = 100;
因为在-128~127的范围内,不会在堆中创建新的对象,而是从常量池中获取值,两者指向一样.所以结果为true.
第三题.Integer a = new Integer(1000);Integer b = 1000;
a没有利用自动装箱的特性,直接在堆中开辟一个新的地址值.而b是利用自动装箱特性,,把基本数据类型转换为对象,在堆中开辟新的地址值.实际上和第一题没什么区别.两者地址值不同,结果false.
第四题:Integer a = new Integer(10);Integer b = new Integer(10);
这两个压根没有利用自动装箱的新特性,相当于两个都是在堆中开辟新的地址值.地址值不同,所以结果为false.

点评

首先感谢你的耐心回答,而且理解的非常正确,对我很有帮助,但是没有看清楚第三题 坑就在这里  发表于 2016-7-4 23:38
回复 使用道具 举报
本帖最后由 cat73 于 2016-7-4 12:59 编辑

附:你可以写一个简单的代码,比如:
  1. public static void main(String[] args) {
  2.     Integer a = 1;
  3. }
复制代码

然后将它编译成 class 文件。
之后用 javap -c 类名 来查看反编译后的结果
然后你就可以看到 Integer.valueOf 了:
  1. cat73@Cat73-PC MINGW64 ~/Desktop
  2. $ javac Test.java

  3. cat73@Cat73-PC MINGW64 ~/Desktop
  4. $ javap -c Test
  5. Compiled from "Test.java"
  6. public class Test {
  7.   public Test();
  8.     Code:
  9.        0: aload_0
  10.        1: invokespecial #1                  // Method java/lang/Object."<init>":()V
  11.        4: return

  12.   public static void main(java.lang.String[]);
  13.     Code:
  14.        0: iconst_1
  15.        1: invokestatic  #2                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
  16.        4: astore_1
  17.        5: return
  18. }
复制代码


请看上面的第 17 行。

点评

感谢详细的回答,对底层知识的理解,我只想问如何能够提高阅读源码的能力? 我想多提高一下,希望技术哥多给点意见呢,关于此题第三个你回答有点问  发表于 2016-7-4 23:54
回复 使用道具 举报
Integer类有个Integer实例的缓冲池,里面准备好了-128到127之间的Integer实例.通过自动装箱给Integer对象赋值时,经判断如果在-128至127之间会直接拿缓冲池里装备好的对象,将它的地址赋值给Integer的引用,如果超出了这个范围才会在堆内存开辟新地址,造Integer对象.由这些知识可知:
第一行结果为false;
第二行结果为true;
第三行与第一行同理,结果为false;
第四行false;

点评

第三个有问题,自己没有测试就回答,坑就在这里  发表于 2016-7-4 23:57
回复 使用道具 举报
九月半 发表于 2016-7-4 08:51
首先,这个问题的前提是Integer类型会自动装箱和自动拆箱.并且在-128到127的范围内,自动装箱不会创建新的对 ...

首先感谢你的回答,而且你的理解非常正确,但是没有仔细看第三题

点评

第三个答案是true,因为包装类型和基本类型比较时,包装类的引用不是地址,而是实际对象,所以是true,我仔细分析过这几道题,,为了赚点黑马币,上就业班,发给大家讨论的,看你这么厉害,以后有问题会请教你,方便给个QQ吗.   发表于 2016-7-5 22:23
至于源码的阅读能力。。。 我也不知道我是怎么练的。。。 不过你看我的注册时间就知道我用 Java 有点时间了。。。 大概是时间长了慢慢就会了吧.....  发表于 2016-7-5 12:01
好吧,a == b 实际是被编译为了 a.intValue() == b,也就是自动拆箱了,所以两个 int 比较,自然是相等的。。  发表于 2016-7-5 08:20
我发现居然是相等的- - 我去研究下原因。。。  发表于 2016-7-5 08:16
的确没注意到内个 int- - 不过这不影响结果吧- - a还是不等于b。。。  发表于 2016-7-5 08:15
回复 使用道具 举报
本帖最后由 pigdanny 于 2016-7-5 18:34 编辑
pigdanny 发表于 2016-7-4 22:45
Integer类有个Integer实例的缓冲池,里面准备好了-128到127之间的Integer实例.通过自动装箱给Integer对象赋 ...

我测试了一下,第三行应该是true.因为Integer和和int比较时会自动拆箱,等价于比较两个int的值,结果自然就是true了.多谢提醒,是我马虎了.

package cn.cast_07;
public class Demo
{

        public static void main(String[] args)
        {
                Integer a=new Integer(1000);
                int b=1000;
                System.out.println(a==b);
                /*
                 * 上面一行等价于
                 * int c=a.intValue();//取出Integer封装的1000赋值给int型变量c
                 * System.out.println(c==b);//此处就等于拿1000和1000比了
                 * */
        }

}



-----------------------------------------
打印结果为true
回复 使用道具 举报
我就来看一看,涨涨知识的。。。
回复 使用道具 举报
主要就是new的位置和取值范围的问题吧,楼上解释很详细啊
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马