Java教程

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

本文主要是介绍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 值。

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

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

反编译为:

    
      
       
      
      
       
        package com.mao.a_box;
       
      
      
       
      
      
        
       
      
      
       
      
      
       
        public 
        class 
        Test01
       
      
      
       
      
      
       
        {
       
      
      
       
      
      
        
       
      
      
       
      
      
       	
        public 
        Test01
        ()
       
      
      
       
      
      
       
        	{
       
      
      
       
      
      
       
        	}
       
      
      
       
      
      
        
       
      
      
       
      
      
       	
        public 
        static 
        void 
        main
        (String args[])
       
      
      
       
      
      
       
        	{
       
      
      
       
      
      
       		
        Integer 
        i 
        = Integer.valueOf(
        10);
       
      
      
       
      
      
       		
        int 
        n 
        = i.intValue();
       
      
      
       
      
      
       
        	}
       
      
      
       
      
      
       
        }
       
      
    

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

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

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

 三、面试中相关的问题

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

    
      
       
      
      
       
        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
       
      
    

输出结果表明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);
       
      
      
       
      
      
       
        }
       
      
    
    
      
       
      
      
       
        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方法会采用与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);
       
      
    

 

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));
       
      
      
       
      
      
       
            }
       
      
      
       
      
      
       
        }
       
      
      
       
      
      
       
        /*true
       
      
      
       
      
      
       
        false
       
      
      
       
      
      
       
        true
       
      
      
       
      
      
       
        true
       
      
      
       
      
      
       
        true
       
      
      
       
      
      
       
        false
       
      
      
       
      
      
       
        true*/
       
      
    

其反编译为:

    
      
       
      
      
       
        package com.mao.a_box;
       
      
      
       
      
      
        
       
      
      
       
      
      
       
        import java.io.PrintStream;
       
      
      
       
      
      
        
       
      
      
       
      
      
       
        public 
        class 
        Main
       
      
      
       
      
      
       
        {
       
      
      
       
      
      
        
       
      
      
       
      
      
       	
        public 
        Main
        ()
       
      
      
       
      
      
       
        	{
       
      
      
       
      
      
       
        	}
       
      
      
       
      
      
        
       
      
      
       
      
      
       	
        public 
        static 
        void 
        main
        (String args[])
       
      
      
       
      
      
       
        	{
       
      
      
       
      
      
       		
        Integer 
        a 
        = Integer.valueOf(
        1);
       
      
      
       
      
      
       		
        Integer 
        b 
        = Integer.valueOf(
        2);
       
      
      
       
      
      
       		
        Integer 
        c 
        = Integer.valueOf(
        3);
       
      
      
       
      
      
       		
        Integer 
        d 
        = Integer.valueOf(
        3);
       
      
      
       
      
      
       		
        Integer 
        e 
        = Integer.valueOf(
        321);
       
      
      
       
      
      
       		
        Integer 
        f 
        = Integer.valueOf(
        321);
       
      
      
       
      
      
       		
        Long 
        g 
        = Long.valueOf(
        3L);
       
      
      
       
      
      
       		
        Long 
        h 
        = Long.valueOf(
        2L);
       
      
      
       
      
      
       
        		System.out.println(c == d);
       
      
      
       
      
      
       
        		System.out.println(e == f);
       
      
      
       
      
      
       
        		System.out.println(c.intValue() == a.intValue() + b.intValue());
       
      
      
       
      
      
       
        		System.out.println(c.equals(Integer.valueOf(a.intValue() + b.intValue())));
       
      
      
       
      
      
       
        		System.out.println(g.longValue() == (
        long)(a.intValue() + b.intValue()));
       
      
      
       
      
      
       
        		System.out.println(g.equals(Integer.valueOf(a.intValue() + b.intValue())));
       
      
      
       
      
      
       
        		System.out.println(g.equals(Long.valueOf((
        long)a.intValue() + h.longValue())));
       
      
      
       
      
      
       
        	}
       
      
      
       
      
      
       
        }
       
      
    

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

 

作者:Matrix海子  

出处:http://www.cnblogs.com/dolphin0520/

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

</article>
这篇关于Java自动装箱与自动拆箱(包装类)的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!