深入解析Java中的装箱和拆箱
下面是本文的文件夹大纲:
一.什么是装箱?什么是拆箱?
二.装箱和拆箱是怎样实现的
三.面试中相关的问题
若有不正之处,请谅解和批评指正。不胜感激。
一.什么是装箱?什么是拆箱?
在前面的文章中提到,Java为每种基本数据类型都提供了相应的包装器类型,至于为什么会为每种基本数据类型提供包装器类型在此不进行阐述,有兴趣的朋友能够查阅相关文档。在Java SE5之前,假设要生成一个数值为10的Integer对象,必须这样进行:
Integer i = new Integer(10);
而在从Java SE5開始就提供了自己主动装箱的特性。假设要生成一个数值为10的Integer对象,仅仅须要这样就能够了:
Integer i = 10;
这个过程中会自己主动依据数值创建相应的 Integer对象。这就是装箱。
那什么是拆箱呢?顾名思义,跟装箱相应,就是自己主动将包装器类型转换为基本数据类型:
Integer i = 10; //装箱
int n = i; //拆箱
简单一点说,装箱就是 自己主动将基本数据类型转换为包装器类型;拆箱就是 自己主动将包装器类型转换为基本数据类型。
下表是基本数据类型相应的包装器类型:
int(4字节) | Integer |
byte(1字节) | Byte |
short(2字节) | Short |
long(8字节) | Long |
float(4字节) | Float |
double(8字节) | Double |
char(2字节) | Character |
boolean(未定) | Boolean |
二.装箱和拆箱是怎样实现的
上一小节了解装箱的基本概念之后,这一小节来了解一下装箱和拆箱是怎样实现的。
我们就以Interger类为例,以下看一段代码:
public class Main {public static void main(String[] args) {Integer i = 10;int n = i;}
}
反编译class文件之后得到例如以下内容:
从反编译得到的字节码内容能够看出。在装箱的时候自己主动调用的是Integer的valueOf(int)方法。而在拆箱的时候自己主动调用的是Integer的intValue方法。
其它的也类似,比方Double、Character,不相信的朋友能够自己手动尝试一下。
因此能够用一句话总结装箱和拆箱的实现过程:
装箱过程是通过调用包装器的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);}
}
或许有些朋友会说都会输出false。或者也有朋友会说都会输出true。可是其实输出结果是:
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];elsereturn new Integer(i);}
而当中IntegerCache类的实现为:
private static class IntegerCache {static final int high;static final Integer cache[];static {final int low = -128;// high value may be configured by propertyint h = 127;if (integerCacheHighPropValue != null) {// Use Long.decode here to avoid invoking methods that// require Integer's autoboxing cache to be initializedint i = Long.decode(integerCacheHighPropValue).intValue();i = Math.max(i, 127);// Maximum array size is Integer.MAX_VALUEh = 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的实现。
在这里仅仅解释一下为什么Double类的valueOf方法会採用与Integer类的valueOf方法不同的实现。非常easy:在某个范围内的整型数值的个数是有限的,而浮点数却不是。
注意,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);
至此。大家应该明确了为何上面输出的结果都是true了。
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));}
}
读者自己想一下这段代码的输出结果是什么。这里面须要注意的是:当 "=="运算符的两个操作数都是 包装器类型的引用,则是比較指向的是否是同一个对象,而假设当中有一个操作数是表达式(即包括算术运算)则比較的是数值(即会触发自己主动拆箱的过程)。另外。对于包装器类型,equals方法并不会进行类型转换。明确了这2点之后,上面的输出结果便一目了然:
true
false
true
true
true
false
true
第一个和第二个输出结果没有什么疑问。第三句因为 a+b包括了算术运算,因此会触发自己主动拆箱过程(会调用intValue方法),因此它们比較的是数值是否相等。而对于c.equals(a+b)会先触发自己主动拆箱过程,再触发自己主动装箱过程。也就是说a+b。会先各自调用intValue方法。得到了加法运算后的数值之后,便调用Integer.valueOf方法,再进行equals比較。同理对于后面的也是这样,只是要注意倒数第二个和最后一个输出的结果(假设数值是int类型的,装箱过程调用的是Integer.valueOf。假设是long类型的。装箱调用的Long.valueOf方法)。
转载于:https://www.cnblogs.com/mengfanrong/p/5419993.html
深入解析Java中的装箱和拆箱相关推荐
- Java中的装箱和拆箱剖析
Java中的装箱和拆箱剖析 自动装箱和拆箱问题是Java中一个老生常谈的问题了,今天我们就来一些看一下装箱和拆箱中的若干问题.本文先讲述装箱和拆箱最基本的东西,再来看一下乐橙谷公会面试笔试中经常遇到的 ...
- java中的拆箱和装箱是指什么_一文带你理解Java中自动装箱和拆箱
Java中自动装箱和拆箱 装箱(Boxing),也称为包装(Wrapper),是在对象中放置原语类型(primitive type)的过程,以便原语(primitive)可以作为引用对象使用. 这里的 ...
- 一文带你理解Java中自动装箱和拆箱
Java中自动装箱和拆箱 装箱(Boxing),也称为包装(Wrapper),是在对象中放置原语类型(primitive type)的过程,以便原语(primitive)可以作为引用对象使用. 这里的 ...
- Java中的装箱和拆箱—这一篇全了解
Java中的拆箱装箱-这一篇全了解 一.什么是装箱?什么是拆箱? Java为每种基本数据类型都提供了对应的包装器类型,让基本类型具备对象的特征,实现更多的功能..在Java SE5之前,如果要生成一个 ...
- java基础提升篇:深入剖析Java中的装箱和拆箱
一.什么是装箱?什么是拆箱? 我们知道 Java为每种基本数据类型都提供了对应的包装器类型,至于为什么会为每种基本数据类型提供包装器类型在此不进行阐述,有兴趣的朋友可以查阅相关资料.在Java SE5 ...
- java中的装箱及拆箱
java中存在8中基本的数据类型,每一种数据类型都有包装类型. 包装类型:每一个基本的数据类型都会------对应一个包装类型. boolean------------------>Boolea ...
- JAVA中的装箱与拆箱
1.定义:装箱是将值类型装换成引用类型的过程:拆箱就是将引用类型转换成值类型的过程: 装箱:用于在垃圾回收堆中储存值类型.装箱是值类型到Object类型或到此类型所实现的任何接口类型的隐式转换. ...
- java避免装箱_深入剖析Java中的装箱和拆箱
一.什么是装箱?什么是拆箱? Java为每种基本数据类型都提供了对应的包装器类型,至于为什么会为每种基本数据类型提供包装器类型在此不进行阐述,有兴趣的朋友可以查阅相关资料.在Java SE5之前,如果 ...
- java装箱与拆箱原理_深入理解Java中的装箱和拆箱
前言 自动装箱和拆箱问题是Java中一个老生常谈的问题了,今天我们就来一些看一下装箱和拆箱中的若干问题.本文先讲述装箱和拆箱最基本的东西,再来看一下面试笔试中经常遇到的与装箱.拆箱相关的问题. 若有不 ...
- java中的装箱和拆箱详解
什么是装箱和拆箱 装箱就是自动将基本数据类型转换为包装器类型. 拆箱就是自动将包装器类型转换为基本数据类型. 装箱和拆箱的原理 自动装箱都是通过包装类的 valueOf() 方法来实现的.自动拆箱都是 ...
最新文章
- uC/OS II--与ECB操作相关的四个函数
- linux多线程信号总结
- 事务对性能影响_MySQL数据库性能优化史诗级大总结
- C++基础部分_C++文件操作_文件的读取操作---C++语言工作笔记077
- 【Spring Cloud】微服务和Spring Cloud
- java商城项目_javaweb实战之商城项目开发(一)
- App跳转到权限设置界面
- 计算机怎么把硬盘分成几个,怎么把硬盘分成整数分区_硬盘分区整数对照表
- html的各种标签详解
- matlab中二维散点图,MATLAB实例:二维散点图
- 20220317北京雪
- 符号速率,码片速率,业务速率,信道编码,扩频因子
- 软件测试常用的工具都在这里了
- SAAS产品有哪些优缺点?
- 木木机器人tf卡_Microsoft 微软 L5V-00022 Sculpt Ergonomic 人体工程学无线键鼠套装
- 【OS】什么是YUM?如何配置本地YUM源?
- 《Attention Is All You Need》注意力机制公式中Q,K,V的理解
- 强化学习第一步:Q_learning 算法,Q现实与Q估计分不清楚?我来说说我的理解
- 用vue实现小米商城登录注册页面
- Matlab如何在一个Figure画两个Legend