精华内容
下载资源
问答
  • 【JAVA】谈谈拆箱与装箱

    万次阅读 多人点赞 2018-11-19 21:40:33
    谈谈装箱与拆箱 一、何为包装类型 Java是一种面向对象的语言,但是它不是纯面向对象的。Java中存在基本数据类型,谈不上对象。为了向纯面向对象靠拢,Java5的时候推出了基本数据类型的包装类型。 基本数据类型与...

                                              谈谈装箱与拆箱

    一、何为包装类型

    Java是一种面向对象的语言,但是它不是纯面向对象的。Java中存在基本数据类型,谈不上对象。为了向纯面向对象靠拢,Java5的时候推出了基本数据类型的包装类型。

    基本数据类型与包装类型的对应关系如下: 



    二、何为装箱与拆箱

    装箱就是将基本数据类型转化为包装类型,那么拆箱就是将包装类型转化为基本数据类型。

    以基本数据类型int为例:

    package day1119;
    
    public class TestBox {
        public static void main(String[] args) {
            //自动装箱,底层其实执行了Integer a=Integer.valueOf(1);
            Integer a = 1;
            //自动拆箱,底层其实执行了int b=a.intValue();
            int b = a;
        }
    }
    

    Integer的valueOf(int i)方法可以将一个基本数据类型转化为对应的包装类型,即装箱方法。

    而Integer的intValue()方法则可以将一个包装类型转化为对应的基本数据类型,即拆箱方法。


    三、装箱与自动装箱的区别

    装箱:利用Integer的构造方法Integer(int value),即Integer c=new Integer(1);

    自动装箱:或者叫隐式装箱,直接给Integer赋值,即Integer d=1,在编译的时候,会调用Integer.valueOf()方法完成装箱。

    相比而言,自动装箱可能比装箱具有更高的效率,体现在自动装箱的缓存上,下面从几道题目来讲自动装箱的缓存。


    四、相关面试题目

    第一题:以下代码的输出结果为?(==号两边如果都是引用类型的话,则判断它们是否指向同一个对象。如果都是基本数据类型的话,则判断它们的数值是否相等)

    package day1119;
    
    public class TestBox2 {
        public static void main(String[] args) {
            Integer a = 100;
            Integer b = 100;
            Integer c = 200;
            Integer d = 200;
            System.out.println(a == b);
            System.out.println(c == d);
        }
    }
    

    也许有些人认为他们是四个各不相同的对象,两个式子都返回false。

    实际运行后发现输出:

    为什么一个是true,一个是false呢?

    刚才我们知道,Integer a=100这条语句会触发自动装箱,而自动装箱的方法为Integer.valueOf()方法,让我们去寻找这个方法,一探究竟。

    观察Integer类的源码中的valueOf()

        /**
         * Returns an {@code Integer} instance representing the specified
         * {@code int} value.  If a new {@code Integer} instance is not
         * required, this method should generally be used in preference to
         * the constructor {@link #Integer(int)}, as this method is likely
         * to yield significantly better space and time performance by
         * caching frequently requested values.
         *
         * This method will always cache values in the range -128 to 127,
         * inclusive, and may cache other values outside of this range.
         *
         * @param  i an {@code int} value.
         * @return an {@code Integer} instance representing {@code i}.
         * @since  1.5
         */
        public static Integer valueOf(int i) {
            if (i >= IntegerCache.low && i <= IntegerCache.high)
                return IntegerCache.cache[i + (-IntegerCache.low)];
            return new Integer(i);
        }
    

    可以看得出,当i的值位于[-128,127]的时候,会直接返回Integer缓存数组中相应对象的引用,如果i大于127或小于-128,会重新创建一个Integer实例,并返回。

    那么第一条式子a和b的值都在缓存范围内,因此他们指向同一个对象,因此返回true。c和d的值不在范围内,都是通过new创建出来的,因此不是同一个对象,返回false。

    注意:Byte、Short、Integer、Long、Character的valueOf()实现机制类似。

    其中相同值的Byte比较永远返回true,因为byte取值范围就是[-128,127]。

    Short、Integer、Long的valueOf()基本一样,i的范围都需要在[-128,127]。

    Character中i的范围只要小于等于127即可,因为char最小值为0,本来就大于等于-128。

    但是Float、Double中的valueOf(),永远返回新创建的对象,因为一个范围内的整数是有限的,但是小数却是无限的,无法保存在缓存中。

    Boolean中只有两个对象,要么是true的Boolean,要么是false的Boolean,只要boolean的值相同,Boolean就相等。


    第二题:以下代码的输出结果为?

    package day1119;
    
    public class TestBox3 {
        public static void main(String[] args) {
            Integer a = 1;
            Integer b = 2;
            Integer c = 3;
            Long d = 2L;
            Long e = 3L;
            int f = 2;
    
            //一旦有包装类型和数值类型判断==时,则触发包装类型的自动拆箱,转为数值类型的比较
            System.out.println(new Integer(300) == 300);//返回true
    
            //一旦有包装类型和数值类型发生运算时,则触发包装类型的自动拆箱,转为数值类型的运算
            System.out.println(c == (a + f));//返回true
    
            //一旦有包装类型和包装类型发生运算时,则触发包装类型的自动拆箱,转为数值类型的运算
            System.out.println(c == (a + b));//返回true
    
            //只有对象类型才有equals方法,因此首先a,b触发包装类型的自动拆箱,转为数值类型的运算。
            //运算完,再将结果3自动装箱,Integer重写了equals,因此可以转为包装类型与包装类型的比较。
            //当两边的包装类型不一致时,必定返回false。
            //当两边的包装类型一致时,再进行拆箱,判断两者代表的数值是否相等。
            System.out.println(c.equals(a + b));//返回true
    
            //不同数据类型的数值进行运算,首先会将低精度的数据类型转化为高精度的数据类型,即自动类型转换。
            //比如现在的int+long,会提升到long+long,再进行运算。
            System.out.println(e == (a + d));//返回true
    
            //==号两边类型不一致时,直接执行自动拆箱,比较之后的数值
            System.out.println(e == (a + b));//返回true
    
            //依次经历自动拆箱,自动类型转换、运算、自动装箱,类型比较,拆箱,数值比较
            System.out.println(e.equals(a + d));//返回true
    
            //依次经历自动拆箱,自动类型转换、运算、自动装箱,类型比较,两边类型不一致,直接返回false
            System.out.println(c.equals(a + d));//返回false
    
    
        }
    }
    

    五、总结

    如果想要深入了解自动装箱拆箱的过程,必须得反编译class文件,了解底层编译的细节,才可以解除自己此方面的疑问。

    展开全文
  • 主要介绍了Java拆箱与装箱,结合实例形式详细分析了Java拆箱与装箱相关的数据类型转换操作技巧,需要的朋友可以参考下
  • java Integer拆箱与装箱

    2020-03-10 12:55:14
    Integer a = 10的时候java会调用Integer.valueOf()方法将a装箱成一个Integer对象. ...当Integernew Integer()对象int变量比较的时候,都会调用Integer的intValue()方法自动拆箱成int型进行对比! ...

    Integer a = 10的时候java会调用Integer.valueOf()方法将a装箱成一个Integer对象.
    ps:装箱的时候,如果两个Integer值相等,并且范围在-128~127,会启动IntegerCache缓存,返回同一个对象
    当Integer与new Integer()对象与int变量比较的时候,都会调用Integer的intValue()方法自动拆箱成int型进行对比!
    因此Integer i=null的时候与int值"=="比较的时候,会报NPE.

    展开全文
  • 通过装箱拆箱操作,能够在值类型和引用类型中架起一做桥梁.换言之,可以轻松的实现值类型引用类型的互相转换
  • 拆箱与装箱

    千次阅读 2016-03-03 10:08:33
    装箱拆箱几乎是所有面试题中必考之一,看上去简单,就往往容易被忽视。其实它一点都不简单的,一个简单的问题也可以从多个层次来解读。  常见面试题目: 1.什么是拆箱装箱? 2.什么是箱子? 3.箱子...

    转载自:http://www.cnblogs.com/anding/p/5236739.html

    装箱和拆箱几乎是所有面试题中必考之一,看上去简单,就往往容易被忽视。其实它一点都不简单的,一个简单的问题也可以从多个层次来解读。

      常见面试题目:

    1.什么是拆箱和装箱?

    2.什么是箱子?

    3.箱子放在哪里?

    4.装箱和拆箱有什么性能影响?

    5.如何避免隐身装箱?

    6.箱子的基本结构?

    7.装箱的过程?

    8.拆箱的过程?

    9.下面这段代码输出什么?共发生多少次装箱?多少次拆箱?

    int i = 5;
    object obj = i;
    IFormattable ftt = i;
    Console.WriteLine(System.Object.ReferenceEquals(i, obj));
    Console.WriteLine(System.Object.ReferenceEquals(i, ftt));
    Console.WriteLine(System.Object.ReferenceEquals(ftt, obj));
    Console.WriteLine(System.Object.ReferenceEquals(i, (int)obj));
    Console.WriteLine(System.Object.ReferenceEquals(i, (int)ftt));

      深入浅出装箱与拆箱

    有拆必有装,有装必有拆。

    在上一文中我们提到,所有值类型都是继承自System.ValueType,而System.ValueType又是来自何方呢,不难发现System.ValueType继承自System.Object。因此Object是.NET中的万物之源,几乎所有类型都来自她,这是装箱与拆箱的基础。

    特别注意的是,本文与上一文有直接关联,需要先了解上一文中值类型与引用类型的原理,才可以更好理解本文的内容。

    微笑 基本概念

    拆箱与装箱就是值类型与引用类型的转换,她是值类型和引用类型之间的桥梁,他们可以相互转换的一个基本前提就是上面所说的:Object是.NET中的万物之源

    先看看一个小小的实例代码:

                int x = 1023;
                object o = x; //装箱
                int y = (int) o; //拆箱

    装箱:值类型转换为引用对象,一般是转换为System.Object类型或值类型实现的接口引用类型;

    拆箱:引用类型转换为值类型,注意,这里的引用类型只能是被装箱的引用类型对象;

    由于值类型和引用类型在内存分配的不同,从内存执行角度看,拆箱与装箱就势必存在内存的分配与数据的拷贝等操作,这也是装箱与拆箱性能影响的根源

    大笑 装箱的过程

    int x = 1023;
    object o = x; //装箱

    装箱就是把值类型转换为引用类型,具体过程:

    • 1.在堆中申请内存,内存大小为值类型的大小,再加上额外固定空间(引用类型的标配:TypeHandle和同步索引块);
    • 2.将值类型的字段值(x=1023)拷贝新分配的内存中;
    • 3.返回新引用对象的地址(给引用变量object o)

    image

    如上图所示,装箱后内存有两个对象:一个是值类型变量x,另一个就是新引用对象o。装箱对应的IL指令为box,上面装箱的IL代码如下图:

    image

    大笑 拆箱的过程

    int x = 1023;
    object o = x; //装箱
    int y = (int) o; //拆箱

    明白了装箱,拆箱就是装箱相反的过程,简单的说是把装箱后的引用类型转换为值类型。具体过程:

    • 1.检查实例对象(object o)是否有效,如是否为null,其装箱的类型与拆箱的类型(int)是否一致,如检测不合法,抛出异常;
    • 2.指针返回,就是获取装箱对象(object o)中值类型字段值的地址;
    • 3.字段拷贝,把装箱对象(object o)中值类型字段值拷贝到栈上,意思就是创建一个新的值类型变量来存储拆箱后的值;

    image

    如上图所示,拆箱后,得到一个新的值类型变量y,拆箱对应的IL指令为unbox,拆箱的IL代码如下:

    image 

    吐舌笑脸 装箱与拆箱总结及性能

    装的的什么?拆的又是什么?什么是箱子?

    通过上面深入了解了装箱与拆箱的原理,不难理解,只有值类型可以装箱,拆的就是装箱后的引用对象,箱子就是一个存放了值类型字段的引用对象实例,箱子存储在托管堆上。只有值类型才有装箱、拆箱两个状态,而引用类型一直都在箱子里

    关于性能

    之所以关注装箱与拆箱,主要原因就是他们的性能问题,而且在日常编码中,经常有装箱与拆箱的操作,而且这些装箱与拆箱的操作往往是在不经意时发生。一般来说,装箱的性能开销更大,这不难理解,因为引用对象的分配更加复杂,成本也更高,值类型分配在栈上,分配和释放的效率都很高。装箱过程是需要创建一个新的引用类型对象实例,拆箱过程需要创建一个值类型字段,开销更低。

    为了尽量避免这种性能损失,尽量使用泛型,在代码编写中也尽量避免隐式装箱。

    什么是隐式装箱?如何避免?

    就是不经意的代码导致多次重复的装箱操作,看看代码就好理解了

    int x = 100;
    ArrayList arr = new ArrayList(3);
    arr.Add(x);
    arr.Add(x);
    arr.Add(x);

    这段代码共有多少次装箱呢?看看Add方法的定义:

    image

    再看看IL代码,可以准确的得到装箱的次数:

    image

    显示装箱可以避免隐式装箱,下面修改后的代码就只有一次装箱了。

    int x = 100;
    ArrayList arr = new ArrayList(3);
    object o = x;
    arr.Add(o);
    arr.Add(o);
    arr.Add(o);

      题目答案解析:

    1.什么是拆箱和装箱?

    装箱就是值类型转换为引用类型,拆箱就是引用类型(被装箱的对象)转换为值类型。

    2.什么是箱子?

    就是引用类型对象。

    3.箱子放在哪里?

    托管堆上。

    4.装箱和拆箱有什么性能影响?

    装箱和拆箱都涉及到内存的分配和对象的创建,有较大的性能影响。

    5.如何避免隐身装箱?

    编码中,多使用泛型、显示装箱。

    6.箱子的基本结构?

    上面说了,箱子就是一个引用类型对象,因此她的结构,主要包含两部分:

    • 值类型字段值;
    • 引用类型的标准配置,引用对象的额外空间:TypeHandle和同步索引块,关于这两个概念在本系列后面的文章会深入探讨。

    7.装箱的过程?

    • 1.在堆中申请内存,内存大小为值类型的大小,再加上额外固定空间(引用类型的标配:TypeHandle和同步索引块);
    • 2.将值类型的字段值(x=1023)拷贝新分配的内存中;
    • 3.返回新引用对象的地址(给引用变量object o)

    8.拆箱的过程?

    • 1.检查实例对象(object o)是否有效,如是否为null,其装箱的类型与拆箱的类型(int)是否一致,如检测不合法,抛出异常;
    • 2.指针返回,就是获取装箱对象(object o)中值类型字段值的地址;
    • 3.字段拷贝,把装箱对象(object o)中值类型字段值拷贝到栈上,意思就是创建一个新的值类型变量来存储拆箱后的值;

    9.下面这段代码输出什么?共发生多少次装箱?多少次拆箱?

    int i = 5;
    object obj = i;
    IFormattable ftt = i;
    Console.WriteLine(System.Object.ReferenceEquals(i, obj));
    Console.WriteLine(System.Object.ReferenceEquals(i, ftt));
    Console.WriteLine(System.Object.ReferenceEquals(ftt, obj));
    Console.WriteLine(System.Object.ReferenceEquals(i, (int)obj));
    Console.WriteLine(System.Object.ReferenceEquals(i, (int)ftt));

    上面代码输出如下,至于发生多少次装箱多少次拆箱,你猜?

    False
    False
    False
    False
    False

     

    版权所有,文章来源:http://www.cnblogs.com/anding

    个人能力有限,本文内容仅供学习、探讨,欢迎指正、交流。

      参考资料:

    书籍:CLR via C#

    书籍:你必须知道的.NET

    1.4.2 装箱和拆箱:http://book.51cto.com/art/201012/237726.htm


    展开全文
  • 自动拆箱与装箱

    2019-08-19 17:57:13
    自动拆箱与装箱 一、自动拆箱与装箱 ... //自动装箱与自动拆箱 int a= 7; Integer b = a;//自动装箱,基本数据类型转化为包装类 int c = b;//自动拆箱,包装类转化为基本数据类型 } } 二、包装类...

    自动拆箱与装箱


      一、自动拆箱与装箱

    public class Test {
    	
    	public static void main(String[] args) {
    		
    		//自动装箱与自动拆箱
    		int a= 7;
    		Integer b = a;//自动装箱,基本数据类型转化为包装类
    		int c = b;//自动拆箱,包装类转化为基本数据类型
    		
    	}
    }
    

     二、包装类数据缓存

    public class Test {
    	
    	public static void main(String[] args) {
    		
    		System.out.println("***************************Java中只是对部分基本数据类型对应包装类的部分数据进行了缓存");
    		
    		//Byte、Long、Integer、Short对-128~127之间的数据进行了缓存,在常量池里面
    		Integer aa = 127;
    		Integer bb = 127;
    		System.out.println(aa==bb);//在-128~127之间,输出为true
    		
    		Integer dd = 128;
    		Integer ee = 128;
    		System.out.println(dd==ee);//不在-128~127之间,输出为false
    		
    		
    		//char所对应包装类的数据缓存范围为 0~127
    		Character cc = 127;
    		Character ff = 127;
    		System.out.println(cc==ff);//在 0~127之间,输出为true
    		
    		cc = 128;
    	    ff = 128;
    		System.out.println(cc==ff);//不在0~127之间,输出为false
    		
    		
    		//Double、Float没有数据缓存范围
    		Double gg = 127.0;
    		Double hh = 127.0;
    		System.out.println(gg==hh);//没有数据缓存,输出为false
    		
    		
    		//Boolean数据缓存为true和false
    		Boolean jj = true;
    		Boolean tt = true;
    		System.out.println(jj==tt);
    		
    		
    	}
    }
    

    三、基本数据类型包装类中的equals方法

    以Integer为例:

    public class Test {
    	
    	public static void main(String[] args) {
    	
    		//包装类中的equals方法,先比较基本数据类型包装类是否相同,不同则返回false,相同则比较值是否相同,相同为true,否则为false
    		Integer aa = 128;
    		Integer bb = 128;
    		Short cc= 128;
    		System.out.println(aa==bb);//不在-128~127之间,输出为false
    		System.out.println(aa.equals(bb));//aa、bb基本数据类型包装类相同,在比较值的大小时自动拆箱,变为int类型,大小相等,输出为true
    		System.out.println(aa.equals(cc));//aa、cc基本数据类型包装类不同,输出为false
    	}
    }
    

    结果

    注意:当基本数据类型包装类执行equals方法与对应的基本数据类型比较,比较的是值的大小

    public class Test {
    	
    	public static void main(String[] args) {
    	
    		Integer aa = 128;
    		int bb = 128;
    		short cc= 128;
    		System.out.println(aa==bb);//输出为true
    		System.out.println(aa.equals(bb));//输出为true
    		System.out.println(aa.equals(cc));//输出为false
    	}
    }

     

    展开全文
  • 1.装箱拆箱的本质 ...利用装箱拆箱功能,可通过允许值类型的任何值Object 类型的值相互转换,将值类型引用类型链接起来 例如: intval = 100; objectobj = val; Console.WriteLine(“对...
  • 学习笔记-拆箱与装箱

    2018-08-17 16:20:35
    拆箱与装箱就是值类型引用类型的转换,她是值类型和引用类型之间的桥梁,他们可以相互转换的一个基本前提就是上面所说的:Object是.NET中的万物之源 先看看一个小小的实例代码: int x = 1023; object o = x;...
  • 装箱拆箱几乎是所有面试题中必考之一,看上去简单,就往往容易被忽视。其实它一点都不简单的,一个简单的问题也可以从多个层次来解读。 常见面试题目: 1.什么是拆箱装箱? 2.什么是箱子? 3.箱子放在哪里? ...
  • 1.什么是拆箱装箱? 2.什么是箱子? 3.箱子放在哪里? 4.装箱拆箱有什么性能影响? 5.如何避免隐身装箱? 6.箱子的基本结构? 7.装箱的过程? 8.拆箱的过程? 9.下面这段代码输出什么?共发生多少次装箱...
  • Java中的拆箱与装箱

    2020-07-03 18:15:22
    我们先来了解一下拆箱与装箱的概念: 装箱:将基本数据类型转换为包装类; 拆箱:将包装类转换为基本数据类型 我们来看两串代码: Integer b1 = 127; Integer b2 = 127; System.out.println(b1==b2);//true ...
  • Java之——拆箱与装箱

    2020-08-24 22:26:30
    自动拆箱与装箱 代码展示 装箱 装箱定义:把基本类型的数据,包装到包装类中。(基本类型的数据->包装类) 基本数据类型(四类八种) 整型:byte/short/int/long 浮点型:float/double 字符型:char ...
  • 1.装箱,值类型向引用类型转换: 在托管堆中分配内存,分配的内存量...2.拆箱,引用类型向值类型转换: 获取已装箱类型中的未装箱部分,也就是对象的原始值的各个字段 复制字段的值从堆中到栈中的值类型实例中...
  • 泛型的拆箱与装箱解读泛型百度百科解读定义分类个人理解及参考解读泛型的使用泛型类泛型接口 泛型 百度百科解读 泛型是程序设计语言的一种特性。允许程序员在强类型程序设计语言中编写代码时定义一些可变部分,那些...
  • java拆箱与装箱

    2018-12-27 09:53:46
    1,java的八种基本数据类型: 整形:byte,short,int,long ... 2,拆箱与装箱 拆箱:把包装类型转成基本数据类型 装箱:把基本数据类型转换成包装类型 基本数据类型 -------------------- 包装类型 byte ...
  • 装箱拆箱的执行过程?常见问题? 1、什么是装箱?什么是拆箱装箱:基本类型转变为包装器类型的过程。 拆箱:包装器类型转变为基本类型的过程。 //JDK1.5之前是不支持自动装箱和自动拆箱的,定义Integer...
  • 拆箱与装箱可能会出现的坑 以Integer为例: 装箱时使用静态的valueOf()方法。 拆箱时使用非静态的xxxValue()方法。 try { int count = (Integer) map.get("count"); } catch (NullPointerException e) { // ...
  • java 拆箱与装箱原理

    2021-03-01 20:22:09
    因为这里的装箱拆箱是自动进行的非人为转换,所以就称作为自动装箱拆箱。原始类型byte, short, char, int, long, float, double 和 boolean 对应的封装类为Byte, Short, Character, Integer, Long, Float, ...
  • 装箱与拆箱

    2018-07-06 14:37:46
    https://www.cnblogs.com/dolphin0520/p/3780005.html

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 58,668
精华内容 23,467
关键字:

拆箱与装箱