Java 自动装箱和拆箱(待整理)

Posted 可持续化发展

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java 自动装箱和拆箱(待整理)相关的知识,希望对你有一定的参考价值。

含义

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

Integer i =10; //装箱
int n = i;  //拆箱

public class Main {
    public static void main(String[] args) {
         
        Integer i =10;
        int n = i;
    }
}

从反编译得到的字节码内容可以看出,在装箱的时候自动调用Integer的valueOf(int)方法。而在拆箱的时候自动调用Integer的intValue方法。
装箱过程是通过调用包装器的valueOf方法实现的,而拆箱过程是通过调用包装器的 xxxValue方法实现的。(xxx代表对应的基本数据类型)。

  1. 自动装箱和拆箱是由编译器来完成的,编译器会在编译期根据语法决定是否进行装箱和拆箱动作。

面试题

  1. 谈谈Integer i = new Integer(xxx)和Integer i =xxx;这两种方式的区别。
      1)第一种方式不会触发自动装箱的过程;而第二种方式会触发;
      2)在执行效率和资源占用上的区别。第二种方式的执行效率和资源占用在一般性情况下要优于第一种情况
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
因为如果数值在[-128,127]之间,便返回指向IntegerCache.cache中已经存在的对象的引用;否则创建一个新的Integer对象。上面的代码中i1和i2的数值为100,因此会直接从cache中取已经存在的对象,所以i1和i2指向的是同一个对象,而i3和i4则是分别指向不同的对象。

其它基本数据类型对应的包装类型的自动装箱池大小
Byte,Short,Integer,Long对应的是-128~127
Character对应的是0~127
Float和Double没有自动装箱池

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

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

public static Long valueOf(long l) {
        final int offset = 128;
        if (l >= -128 && l <= 127) { // will cache
            return LongCache.cache[(int)l + offset];
        }
        return new Long(l);
    }
public static Short valueOf(short s) {
        final int offset = 128;
        int sAsInt = s;
        if (sAsInt >= -128 && sAsInt <= 127) { // must cache
            return ShortCache.cache[sAsInt + offset];
        }
        return new Short(s);
    }
public static Character valueOf(char c) {
        if (c <= 127) { // must cache
            return CharacterCache.cache[(int)c];
        }
        return new Character(c);
    }

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

public static Double valueOf(double d) {
        return new Double(d);
    }
public static Float valueOf(float f) {
        return new Float(f);
    }
  1. 当 "=="运算符的两个操作数都是 包装器类型的引用,则是比较指向的是否是同一个对象,当然还要考虑一下自动装箱池这个因素。而如果其中有一个操作数是表达式(即包含算术运算)则比较的是数值(即会触发自动拆箱的过程)。
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));//Long对象.equals(Integer对象或者int)-> 返回false。
        System.out.println(g.equals(a+h));
    }
}
true
false
true
true
true
false
true

第三句由于 a+b包含了算术运算,因此会触发自动拆箱过程(会调用intValue方法),因此它们比较的是数值是否相等。而对于c.equals(a+b)会先触发自动拆箱过程,再触发自动装箱过程,也就是说a+b,会先各自调用intValue方法,得到了加法运算后的数值之后,便调用Integer.valueOf方法,再进行equals比较。

	public  void demo2(){
        Integer integer100 = 100;
        int int100 = 100;
        Long long200 = 200l;
        System.out.println(long200.equals(integer100 + int100));
    }

结果输出为false。
分析过程:
①integer100+int100就会得到一个类型为int且value为200的基础数据类型a
②Long的equals方法将a进行装箱,装箱所得到的是类型为Integer的对象b
③因为b与long200为不同的类型的对象,所以输出false;
图中 obj 必须为 Long的的实例时才返回数值
如果传入的类型不是Long,那么全部返回false,这就是原因。

总结:Long 与 相同值的 包装类 用equals比较时,如果传入的类型不是Long,那么全部返回false

		Long aa = 3L;
    	Integer b = 3;
    	int c = 3;
    	Object o = c+aa;
    	Object o1 = b+aa;
    	System.out.println(o instanceof Long);
    	System.out.println(o1 instanceof Long);
    	true
		true

 
 Integer integer1 = 100;

       Integer integer2 = 100;

       System.out.println("integer1==integer2: " + (integer1 == integer2));// true 自动装箱的两个缓存中的 Integer对象的引用比较

       System.out.println("integer1.equals(integer2): " + (integer1.equals(integer2)));// true

       System.out.println("integer1.compare(integer2): " + integer1.compareTo(integer2));// 0      
       Integer integer5 =new Integer(100);

       Integer integer6 =new Integer(100);

       System.out.println("integer5==integer6: " + (integer5 == integer6));// false两个不同的Integer对象引用的比较

       System.out.println("integer5.equals(integer6): " + (integer5.equals(integer6)));// true

       System.out.println("integer5.compare(integer6): " + integer5.compareTo(integer6));// 0   

       int int1 = 100;

       System.out.println("integer1==int1: " + (integer1 == int1));// true Integer缓存对象拆箱后与int比较

       System.out.println("integer1.equals(int1): " + (integer1.equals(int1)));// true

       System.out.println("integer1.compare(int1): " + integer1.compareTo(int1));// 0      

       int int2 = 200;

       System.out.println("integer3==int2: " + (integer3 == int2));// true Integer对象拆箱后与int比较

       System.out.println("integer3.equals(int2): " + (integer3.equals(int2)));// true

       System.out.println("integer3.compare(int2): " + integer3.compareTo(int2));// 0

       -XX:AutoBoxCacheMax=<size>这个选项真的可以改变Integer的缓存大小。   

以上是关于Java 自动装箱和拆箱(待整理)的主要内容,如果未能解决你的问题,请参考以下文章

装箱和拆箱---JAVA基础篇

java 啥是拆箱和装箱,拆箱和装箱 嘛用啊???

由自动装箱和拆箱引发我看Integer源码

为啥我们在 Java 中使用自动装箱和拆箱?

[Java基础]自动装箱和拆箱

JAVA——装箱和拆箱