java自动装箱拆箱特性

版权声明:转载请注明:beOkWithAnything总结 https://blog.csdn.net/swq463/article/details/84677856

 http://www.cnblogs.com/dolphin0520/p/3780005.html

在Java SE5 之前,如果要生成一个数值为10的Integer对象,必须这样进行:

Integer i = new Integer(10);

而在 从Java SE5开始  就提供了 自动装箱 的特性,如果要生成一个数值为10的Integer对象,只需要这样就可以了:

Integer i = 10;

这个过程中会自动根据数值创建对应的 Integer对象,这就是装箱。

Integer i = 10;  //装箱

int n = i;   //拆箱

简单一点说:

装箱就是  自动将基本数据类型转换为包装器类型;

拆箱就是  自动将包装器类型转换为基本数据类型。

在装箱的时候自动调用的是 Integer的 valueOf( )  方法

在拆箱的时候自动调用的是 Integer的 intValue( )  方法

扫描二维码关注公众号,回复: 4336784 查看本文章

最关键的下面的面试问题:

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

控制台结果:
true
false

为什么是这个结果呢

看一哈 Integer 的 valueOf( ) 方法的具体实现:

public static Integer valueOf(int i) {
        
        if( i >= -128 && i <= IntegerCache.high )
            /* 如果传入的 int 在 [-128,127] 之间,便返回
               指向IntegerCache.cache中已经存在的对象的引用 */
            return IntegerCache.cache[i + 128];
        else
            // 否则创建一个新的Integer对象
            return new Integer(i);
    }

我对这个 自动装箱 过程的理解是 :

java 5 之后 ,java的开发者已经 默认准备了 [-128,127] 之间的128*2个 Integer 对象了,

这128*2个对象就像常量一样被调用。

如果传入的数字在此范围内( 比如 i1、i2 ),则返回的都是人家提前备好的128*2个对象的引用

超出此范围的话才会去创建新的对象并返回新对象的引用( 比如 i3、i4 ),

而每个新对象的引用又都是不一样的,才导致了以上结果。

扩展:

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

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

Double类的 valueOf( ) 方法会采用与 Integer 类的 valueOf( ) 方法不同的实现

原因:在某个范围内的整型数值的个数是有限的(128*2),而浮点数却是无限的,没有办法提前准备

至于 Boolean包装类 就更简单了,总共只能有两个值,直接就准备好两个静态final对象就好了:

public static final Boolean TRUE = new Boolean(true);

   
public static final Boolean FALSE = new Boolean(false);


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

练习:

(1) '=='比较的是a和b的地址,即比较a和b指向的是否是同一个对象

(2) 对于 ' Integer==int ' 类似的比较,即两个操作数中有一个是(int) 的情况, 比较的是数值是否相等(即Integer类型的那个对象会触发自动拆箱的过程)

 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));
    }

1)c == d  为 true 不用多讲,自动装箱时用的是一个对象

2)e == f   为false 也不多说 , 自动装箱时超出了范围[ -128,127 ],e和f都是新创建的对象,两个对象的地址自然不一样

3)a+b 时会触发自动拆箱操作(为什么? a和b两个都是对象不拆箱怎么进行相加运算?当然要转化成基本数据类型才能+),加完以后变成了 c == (int) ,根据以上(2),c会自动拆箱,即最后比较的是数值

4)c.equals(a+b) 会先触发自动拆箱过程(a+b),再触发自动装箱过程(为什么?相加的结果是作为参数传入c.equals()方法中的,equals()要的当然是Object,当然要装一波箱),也就是说a+b,会先各自调用各自的 intValue() 方法,得到了加法运算后的数值之后,便调用 Integer.valueOf() 方法,再和c进行equals比较

5)同3):用到了(2):a+b之后为int型,Long要触发自动拆箱

6)a+b 的结果自动装箱的时候调用的是Integer.valueOf() 方法,但 g 是用的Long里提前存好的[ -128,127 ]内的对象,而 a+b 用 是Integer里提前存好[ -127,128 ]的对象,连类型都不一样,当然是不同的两个对象

7)a和h 自动拆箱后,运算时 a会自动类型转换成范围更大的 long ,自动装箱时调用的是 Long.valueOf() 方法

运行结果:

true
false
true
true
true
false
true

如果对上面的具体执行过程有疑问,可以尝试获取反编译的字节码内容进行查看:

https://blog.csdn.net/swq463/article/details/84678142

这是代码加反编译的结果:

public static void main(String[] args) {

    Integer b = 3; // Method java/lang/Integer.valueOf 自动装箱

    Long c = 3L; // Method java/lang/Long.valueOf 自动装箱

    System.out.println(c.equals(a)); // Method java/lang/Integer.valueOf a先自动装箱
                                     // Method java/lang/Long.equals 
}

猜你喜欢

转载自blog.csdn.net/swq463/article/details/84677856