黑马程序员技术交流社区

标题: 练习题求解 [打印本页]

作者: LoveGG    时间: 2016-7-4 00:07
标题: 练习题求解

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

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

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

作者: cat73    时间: 2016-7-4 00:07
本帖最后由 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。
作者: 九月半    时间: 2016-7-4 08:51
首先,这个问题的前提是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.

作者: cat73    时间: 2016-7-4 12:56
本帖最后由 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 行。
作者: pigdanny    时间: 2016-7-4 22:45
Integer类有个Integer实例的缓冲池,里面准备好了-128到127之间的Integer实例.通过自动装箱给Integer对象赋值时,经判断如果在-128至127之间会直接拿缓冲池里装备好的对象,将它的地址赋值给Integer的引用,如果超出了这个范围才会在堆内存开辟新地址,造Integer对象.由这些知识可知:
第一行结果为false;
第二行结果为true;
第三行与第一行同理,结果为false;
第四行false;
作者: LoveGG    时间: 2016-7-4 23:36
九月半 发表于 2016-7-4 08:51
首先,这个问题的前提是Integer类型会自动装箱和自动拆箱.并且在-128到127的范围内,自动装箱不会创建新的对 ...

首先感谢你的回答,而且你的理解非常正确,但是没有仔细看第三题
作者: pigdanny    时间: 2016-7-5 18:33
本帖最后由 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

作者: qq1114211383    时间: 2016-7-5 22:21
我就来看一看,涨涨知识的。。。
作者: 小牛想成为大牛    时间: 2016-11-2 23:22
主要就是new的位置和取值范围的问题吧,楼上解释很详细啊




欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2