Java - 装箱 / 拆箱(下)

简介: Java - 装箱 / 拆箱(下)

也许有些朋友会说都会输出false,或者也有朋友会说都会输出true。但是事实上输出结果是:

true
false

  为什么会出现这样的结果?输出结果表明i1和i2指向的是同一个对象,而i3和i4指向的是不同的对象。此时只需一看源码便知究竟,下面这段代码是Integer的valueOf方法的具体实现:

public static Integer valueOf(int i) {
        if(i >= -128 && i <= IntegerCache.high)
            return IntegerCache.cache[i + 128];
        else
            return new Integer(i);
}


而其中IntegerCache类的实现为:

 private static class IntegerCache {
        static final int high;
        static final Integer cache[];
        static {
            final int low = -128;
            // high value may be configured by property
            int h = 127;
            if (integerCacheHighPropValue != null) {
                // Use Long.decode here to avoid invoking methods that
                // require Integer's autoboxing cache to be initialized
                int i = Long.decode(integerCacheHighPropValue).intValue();
                i = Math.max(i, 127);
                // Maximum array size is Integer.MAX_VALUE
                h = Math.min(i, Integer.MAX_VALUE - -low);
            }
            high = h;
            cache = new Integer[(high - low) + 1];
            int j = low;
            for(int k = 0; k < cache.length; k++)
                cache[k] = new Integer(j++);
        }
        private IntegerCache() {}
}

从这2段代码可以看出,在通过valueOf方法创建Integer对象的时候,如果数值在[-128,127]之间,便返回指向IntegerCache.cache中已经存在的对象的引用;否则创建一个新的Integer对象。


 上面的代码中i1和i2的数值为100,因此会直接从cache中取已经存在的对象,所以i1和i2指向的是同一个对象,而i3和i4则是分别指向不同的对象。


2.下面这段代码的输出结果是什么?


/

public class Main {
  public static void main(String[] args) {
    Double i1 = 100.0;
    Double i2 = 100.0;
    Double i3 = 200.0;
    Double i4 = 200.0;
    System.out.println(i1==i2);
    System.out.println(i3==i4);
  }
}

也许有的朋友会认为跟上面一道题目的输出结果相同,但是事实上却不是。实际输出结果为:

false
false

至于具体为什么,读者可以去查看Double类的valueOf的实现。


 在这里只解释一下为什么Double类的valueOf方法会采用与Integer类的valueOf方法不同的实现。很简单:在某个范围内的整型数值的个数是有限的,而浮点数却不是。


 注意:Integer、Short、Byte、Character、Long这几个类的valueOf方法的实现是类似的。


    Double、Float的valueOf方法的实现是类似的。


3.下面这段代码输出结果是什么:

public class Main {
  public static void main(String[] args) {
    Boolean i1 = false;
    Boolean i2 = false;
    Boolean i3 = true;
    Boolean i4 = true;
    System.out.println(i1==i2);
    System.out.println(i3==i4);
  }
}

输出结果是:

true
true  

至于为什么是这个结果,同样地,看了Boolean类的源码也会一目了然。下面是Boolean的valueOf方法的具体实现:

public static Boolean valueOf(boolean b) {
        return (b ? TRUE : FALSE);
}

而其中的 TRUE 和FALSE又是什么呢?在Boolean中定义了2个静态成员属性:

    public static final Boolean TRUE = new Boolean(true);
    /** 
     * The <code>Boolean</code> object corresponding to the primitive 
     * value <code>false</code>. 
     */
    public static final Boolean FALSE = new Boolean(false);

至此,大家应该明白了为何上面输出的结果都是true了。


4.谈谈Integer i = new Integer(xxx)和Integer i =xxx;这两种方式的区别。


 当然,这个题目属于比较宽泛类型的。但是要点一定要答上,我总结一下主要有以下这两点区别:


 1)第一种方式不会触发自动装箱的过程;而第二种方式会触发;


 2)在执行效率和资源占用上的区别。第二种方式的执行效率和资源占用在一般性情况下要优于第一种情况(注意这并不是绝对的)。


5.下面程序的输出结果是什么?


/

public class Main {
  public static void main(String[] args) {
    Integer a = 1;
    Integer b = 2;
    Integer c = 3;
    Integer d = 3;
    Integer e = 321;
    Integer f = 321;
    Long g = 3L;
    Long h = 2L;
    System.out.println(c==d);
    System.out.println(e==f);
    System.out.println(c==(a+b));
    System.out.println(c.equals(a+b));
    System.out.println(g==(a+b));
    System.out.println(g.equals(a+b));
    System.out.println(g.equals(a+h));
  }
}

先别看输出结果,读者自己想一下这段代码的输出结果是什么。这里面需要注意的是:当 "=="运算符的两个操作数都是 包装器类型的引用,则是比较指向的是否是同一个对象,而如果其中有一个操作数是表达式(即包含算术运算)则比较的是数值(即会触发自动拆箱的过程)。另外,对于包装器类型,equals方法并不会进行类型转换。明白了这2点之后,上面的输出结果便一目了然:



/

true
false
true
true
true
false
true

第一个和第二个输出结果没有什么疑问。第三句由于  a+b包含了算术运算,因此会触发自动拆箱过程(会调用intValue方法),因此它们比较的是数值是否相等。而对于c.equals(a+b)会先触发自动拆箱过程,再触发自动装箱过程,也就是说a+b,会先各自调用intValue方法,得到了加法运算后的数值之后,便调用Integer.valueOf方法,再进行equals比较。同理对于后面的也是这样,不过要注意倒数第二个和最后一个输出的结果(如果数值是int类型的,装箱过程调用的是Integer.valueOf;如果是long类型的,装箱调用的Long.valueOf方法)(如下 equals 源码)。


/

    /**
     * Compares this object to the specified object.  The result is
     * {@code true} if and only if the argument is not
     * {@code null} and is a {@code Long} object that
     * contains the same {@code long} value as this object.
     *
     * @param   obj   the object to compare with.
     * @return  {@code true} if the objects are the same;
     *          {@code false} otherwise.
     */
    public boolean equals(Object obj) {
        if (obj instanceof Long) {
            return value == ((Long)obj).longValue();
        }
        return false;
    }
目录
相关文章
|
4月前
|
存储 Java 编译器
Java零基础(12) - 自动装箱
【8月更文挑战第12天】🏆本文收录于「滚雪球学Java」专栏,专业攻坚指数级提升,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!!
35 2
|
4月前
|
Java
【Java基础面试九】、说一说自动装箱、自动拆箱的应用场景
这篇文章介绍了Java中的自动装箱和自动拆箱概念:自动装箱允许将基本类型赋值给对应的包装类对象,而自动拆箱允许将包装类对象赋值给基本类型,从而简化了两者之间的转换过程。
【Java基础面试九】、说一说自动装箱、自动拆箱的应用场景
|
4月前
|
存储 缓存 Java
Java零基础教学(13):自动拆箱与自动装箱详解
【8月更文挑战第13天】Java零基础教学篇,手把手实践教学!
45 1
Java零基础教学(13):自动拆箱与自动装箱详解
|
4月前
|
存储 Java 编译器
Java零基础(17) - 自动拆箱与自动装箱
【8月更文挑战第17天】🏆本文收录于「滚雪球学Java」专栏,专业攻坚指数级提升,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!!
45 3
|
4月前
|
存储 Java 测试技术
Java零基础教学(11):自动装箱
【8月更文挑战第11天】Java零基础教学篇,手把手实践教学!
57 5
|
4月前
|
Java 编译器 测试技术
Java零基础(13) - 自动拆箱
【8月更文挑战第13天】🏆本文收录于「滚雪球学Java」专栏,专业攻坚指数级提升,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!!
33 2
|
4月前
|
Java 编译器 测试技术
Java零基础教学(12):自动拆箱
【8月更文挑战第12天】Java零基础教学篇,手把手实践教学!
38 2
|
5月前
|
Java 编译器 测试技术
day19:Java零基础 - 自动装箱
【7月更文挑战第19天】🏆本文收录于「滚雪球学Java」专栏,专业攻坚指数级提升,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!!
58 4
|
5月前
|
存储 Java 测试技术
day20:Java零基础 - 自动拆箱
【7月更文挑战第20天】🏆本文收录于「滚雪球学Java」专栏,专业攻坚指数级提升,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!!
43 2
|
6月前
|
缓存 Java 编译器
Java自动装箱与拆箱(AutoBoxing_UnBoxing)
Java自动装箱与拆箱(AutoBoxing_UnBoxing)
50 4