Java自动装箱与自动拆箱(包装类)

https://blog.csdn.net/weixin_40556448/article/details/92060659

一、基本介绍

包装类的作用: Java 语言中,一切都是对象,但是有例外: 8 个基本数据类型不是对象,因此在很多时候非常不方便。 为此, Java提供为 8 个基本类型提供了对应的包装类:
                       byte ------- Byte 
                       short ------ Short 
                       int ---------- Integer 
                       long -------- Long 
                       char -------- Character 
                       float -------- Float                                                                                                                                                                                 double ----- Double 
                       boolean----- Boolean 

包装类如何使用? JDK1.5  新增了 2 个功能:自动装箱自动拆箱

  • 自动装箱 当我们把一个基本类型的值( 20),赋值给引用变量时候,系统可以 自动将它包装为相应的包装类的实例程序需要对象时, 如果给的只是一个基本类型的值, 系统会将它自动装箱为包装类的实例达到的效果: 有了自动装箱之后, 基本类型的值可以当成对象用—— 其实是【假相】
  • 自动拆箱 当我们需要一个基本类型的值时, 但实际上传入的包装类的对象。 统会自动把对象开,得到它的值。 达到的效果: 有了自动拆箱之后, 包装类的对象可当成基本类型的值 ——其实是【假相】

自动装箱 ----- 基本类型的值包装类的实例

自动拆箱 ----- 基本类型的值 ← 包装类的实例

事实上,包装类比基本类型更好用——基本类型能做的事情,包装类也能做。 但包装类能做的,基本类型不一定能做,比 如要赋一个 null 值。

二、装箱和拆箱是如何实现的

  1. public class Main {
  2.     public static void main(String[] args) {        
  3.         Integer i = 10;
  4.         int n = i;
  5.     }
  6. }

反编译为:

  1. package com.mao.a_box;
  2. public class Test01
  3. {
  4. public Test01()
  5. {
  6. }
  7.        public static void main(String args[])
  8.        {
  9.               Integer i = Integer.valueOf(10);
  10.               int n = i.intValue();
  11.        }
  12. }

        从反编译得到的字节码内容可以看出,在装箱的时候自动调用的是IntegervalueOf(int)方法。而在拆箱的时候自动调用的是IntegerintValue方法

因此可以用一句话总结装箱和拆箱的实现过程:

  装箱过程是通过调用包装器的valueOf方法实现的,而拆箱过程是通过调用包装器的 xxxValue方法实现的。(xxx代表对应的基本数据类型)

 三、面试中相关的问题

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

  1. public class Main {
  2.     public static void main(String[] args) {
  3.          
  4.         Integer i1 = 100;
  5.         Integer i2 = 100;
  6.         Integer i3 = 200;
  7.         Integer i4 = 200;
  8.          
  9.         System.out.println(i1==i2);
  10.         System.out.println(i3==i4);
  11.     }
  12. }
  13. //true
  14. //false

输出结果表明i1i2指向的是同一个对象,而i3i4指向的是不同的对象。此时只需一看源码便知究竟,下面这段代码是IntegervalueOf方法的具体实现:

  1. public static Integer valueOf(int i) {
  2.         if(i >= -128 && i <= IntegerCache.high)
  3.             return IntegerCache.cache[i + 128];
  4.         else
  5.             return new Integer(i);
  6. }
  1. private static class IntegerCache {
  2.         static final int high;
  3.         static final Integer cache[];
  4.         static {
  5.             final int low = -128;
  6.             // high value may be configured by property
  7.             int h = 127;
  8.             if (integerCacheHighPropValue != null) {
  9.                 // Use Long.decode here to avoid invoking methods that
  10.                 // require Integer's autoboxing cache to be initialized
  11.                 int i = Long.decode(integerCacheHighPropValue).intValue();
  12.                 i = Math.max(i, 127);
  13.                 // Maximum array size is Integer.MAX_VALUE
  14.                 h = Math.min(i, Integer.MAX_VALUE - -low);
  15.             }
  16.             high = h;
  17.             cache = new Integer[(high - low) + 1];
  18.             int j = low;
  19.             for(int k = 0; k < cache.length; k++)
  20.                 cache[k] = new Integer(j++);
  21.         }
  22.         private IntegerCache() {}
  23.     }

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

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

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

  1. public class Main {
  2.     public static void main(String[] args) {
  3.          
  4.         Double i1 = 100.0;
  5.         Double i2 = 100.0;
  6.         Double i3 = 200.0;
  7.         Double i4 = 200.0;
  8.          
  9.         System.out.println(i1==i2);
  10.         System.out.println(i3==i4);
  11.     }
  12. }
  13. //false
  14. //false

在这里只解释一下为什么Double类的valueOf方法会采用与Integer类的valueOf方法不同的实现。

很简单:在某个范围内的整型数值的个数是有限的,而浮点数却不是

  注意,IntegerShortByteCharacterLong这几个类的valueOf方法的实现是类似的。

     DoubleFloatvalueOf方法的实现是类似的。

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

  1. public class Main {
  2.     public static void main(String[] args) {
  3.          
  4.         Boolean i1 = false;
  5.         Boolean i2 = false;
  6.         Boolean i3 = true;
  7.         Boolean i4 = true;
  8.          
  9.         System.out.println(i1==i2);
  10.         System.out.println(i3==i4);
  11.     }
  12. }
  13. //true
  14. //true

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

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

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

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

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

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

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

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

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

  1. public class Main {
  2.     public static void main(String[] args) {
  3.          
  4.         Integer a = 1;
  5.         Integer b = 2;
  6.         Integer c = 3;
  7.         Integer d = 3;
  8.         Integer e = 321;
  9.         Integer f = 321;
  10.         Long g = 3L;
  11.         Long h = 2L;
  12.          
  13.         System.out.println(c==d);
  14.         System.out.println(e==f);
  15.         System.out.println(c==(a+b));
  16.         System.out.println(c.equals(a+b));
  17.         System.out.println(g==(a+b));
  18.         System.out.println(g.equals(a+b));
  19.         System.out.println(g.equals(a+h));
  20.     }
  21. }
  22. /*true
  23. false
  24. true
  25. true
  26. true
  27. false
  28. true*/

其反编译为:

  1. package com.mao.a_box;
  2. import java.io.PrintStream;
  3. public class Main
  4. {
  5. public Main()
  6. {
  7.        }
  8.        public static void main(String args[])
  9.        {
  10.               Integer a = Integer.valueOf(1);
  11.               Integer b = Integer.valueOf(2);
  12.               Integer c = Integer.valueOf(3);
  13.               Integer d = Integer.valueOf(3);
  14.               Integer e = Integer.valueOf(321);
  15.               Integer f = Integer.valueOf(321);
  16.               Long g = Long.valueOf(3L);
  17.               Long h = Long.valueOf(2L);
  18.               System.out.println(c == d);
  19.               System.out.println(e == f);
  20.               System.out.println(c.intValue() == a.intValue() + b.intValue());
  21.        System.out.println(c.equals(Integer.valueOf(a.intValue() + b.intValue())));
  22.               System.out.println(g.longValue() == (long)(a.intValue() + b.intValue()));
  23.        System.out.println(g.equals(Integer.valueOf(a.intValue() + b.intValue())));
  24.        System.out.println(g.equals(Long.valueOf((long)a.intValue() + h.longValue())));
  25.        }
  26. }

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

即运算如==,+等操作会自动拆箱,并且类型会转换,而equals方法是对象比较,只会自动装箱。+

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值