Java中自动装箱与拆箱
一、什么是封装类?
Java中存在基础数据类型,但是在某些情况下,我们要对基础数据类型进行对象的操作,例如,集合中只能存在对象,而不能存在基础数据类型,于是便出现了包装器类。包装器类型就是对基本数据类型进行了封装,使之成为一个对象,每一个基本数据类型都对应一种包装器类型。

二、什么是装箱与拆箱
将基本数据类型变为包装器类,便是装箱,将包装器类转为基本数据类型就是拆箱。相面以Integer为例:
public static void main(String[] args){
//自动装箱
Integer a = 100;
//自动拆箱
int b = a;
}
实际上,Integer在装箱过程中调用了Integer中的valueOf()方法,拆箱为int时调用了Integer中的intValue()方法,源码如下:
public static Integer valueOf(int i) {
assert IntegerCache.high >= 127;
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
public int intValue() {
return value;
}
这便是装箱与拆箱的底层执行过程,其它包装器类类似。
三、自动装箱与拆箱中的一些问题
问题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); //true
System.out.println(i3==i4); //false
}
}
通过分析valueOf()方法我们知道,当值为-128到127之间时,返回return IntegerCache.cache[i + (-IntegerCache.low)];当不在这个区间时,返回return new Integer(i);那么IntegerCache.cache[i + (-IntegerCache.low)]又是什么呢?继续追踪源码:
private static class IntegerCache {
static final int low = -128;
static final int high;
static final Integer cache[];
static {
// high value may be configured by property
int h = 127;
String integerCacheHighPropValue =
sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
if (integerCacheHighPropValue != null) {
int i = parseInt(integerCacheHighPropValue);
i = Math.max(i, 127);
// Maximum array size is Integer.MAX_VALUE
h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
}
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() {}
}
从上面代码可以看出Integer类中提前就初始化了一个Integer数组,范围为-128到127。回到上面的题目:i1==i2=100返回true是因为范围属于-128到127,直接返回cache[]数组中的对象,属于同一个对象,==运算符比较对象,从而返回true,而200超过了这个范围,直接返回new Integer(),因此属于两个不同的对象,结果为false。
问题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); //false
System.out.println(i3==i4); //false
}
}
上面的代码中的结果与Integer类型的结果大相径庭,原因还得从源码中找。
public static Double valueOf(double d) {
return new Double(d);
}
因此返回false理所当然。
总结一下:
Integer派别:Integer、Short、Byte、Character、Long这几个类的valueOf方法的实现是类似的。
Double派别:Double、Float的valueOf方法的实现是类似的。每次都返回不同的对象。
Integer派别的范围:

问题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);//true
System.out.println(i3==i4);//true
}
}
以上代码又是林外一种情况,继续追踪源码
public static Boolean valueOf(boolean b) {
return (b ? TRUE : FALSE);
}
/**
* The {@code Boolean} object corresponding to the primitive
* value {@code true}.
*/
public static final Boolean TRUE = new Boolean(true); /**
* The {@code Boolean} object corresponding to the primitive
* value {@code false}.
*/
public static final Boolean FALSE = new Boolean(false);
分析可知,TRUE和FALSE是两个final对象,因此i1、i2和i3、i4始终指向同一个对象的地址,因此返回true。
问题4:
public static void main(String[] args) {
Integer num1 = 400;
int num2 = 400;
System.out.println(num1 == num2); //true
System.out.println(num1.equals(num2)); //true
}
可见num1 == num2进行了拆箱操作。equals源码如下:
public boolean equals(Object obj) {
if (obj instanceof Integer) {
return value == ((Integer)obj).intValue();
}
return false;
}
我们知道equal比较的是内容本身,并且我们也可以看到equal的参数是一个Object对象,我们传入的是一个int类型,所以首先会进行装箱,然后比较,之所以返回true,是由于它比较的是对象里面的value值。
问题5:
public static void main(String[] args) {
Integer num1 = 100;
int num2 = 100;
Long num3 = 200l;
System.out.println(num1 + num2); //200
System.out.println(num3 == (num1 + num2)); //true
System.out.println(num3.equals(num1 + num2)); //false
}
当一个基础数据类型与封装类进行==、+、-、*、/运算时,会将封装类进行拆箱,对基础数据类型进行运算。
对于num3.equals(num1 + num2)为false的原因很简单,我们还是根据代码实现来说明:
public boolean equals(Object obj) {
if (obj instanceof Long) {
return value == ((Long)obj).longValue();
}
return false;
}
它必须满足两个条件才为true:
1、类型相同
2、内容相同
上面返回false的原因就是类型不同。
问题6:
public static void main(String[] args) {
int num1 = 100;
int num2 = 200;
long mum3 = 300;
System.out.println(mum3 == (num1 + num2)); //true
}
当 “==”运算符的两个操作数都是包装器类型的引用,则是比较指向的是否是同一个对象,而如果其中有一个操作数是表达式(即包含算术运算)则比较的是数值(即会触发自动拆箱的过程)。
问题7:
public static void main(String[] args) {
Integer integer100=null;
int int100=integer100;
}
这两行代码是完全合法的,完全能够通过编译的,但是在运行时,就会抛出空指针异常。其中,integer100为Integer类型的对象,它当然可以指向null。但在第二行时,就会对integer100进行拆箱,也就是对一个null对象执行intValue()方法,当然会抛出空指针异常。所以,有拆箱操作时一定要特别注意封装类对象是否为null。
Java中自动装箱与拆箱的更多相关文章
- 深入剖析Java中的装箱和拆箱
深入剖析Java中的装箱和拆箱 自动装箱和拆箱问题是Java中一个老生常谈的问题了,今天我们就来一些看一下装箱和拆箱中的若干问题.本文先讲述装箱和拆箱最基本的东西,再来看一下面试笔试中经常遇到的与装箱 ...
- 从别人那淘的知识 深入剖析Java中的装箱和拆箱
(转载的海子的博文 海子:http://www.cnblogs.com/dolphin0520/) 深入剖析Java中的装箱和拆箱 自动装箱和拆箱问题是Java中一个老生常谈的问题了,今天我们就来 ...
- 第六节:详细讲解Java中的装箱与拆箱及其字符串
前言 大家好,给大家带来详细讲解Java中的装箱与拆箱及其字符串的概述,希望你们喜欢 装箱与拆箱 封装类有:Byte , short , Integer , Character , long , Fl ...
- [ 转载 ]学习笔记-深入剖析Java中的装箱和拆箱
深入剖析Java中的装箱和拆箱 自动装箱和拆箱问题是Java中一个老生常谈的问题了,今天我们就来一些看一下装箱和拆箱中的若干问题.本文先讲述装箱和拆箱最基本的东西,再来看一下面试笔试中经常遇到的与装箱 ...
- 【转】深入剖析Java中的装箱和拆箱
深入剖析Java中的装箱和拆箱 自动装箱和拆箱问题是Java中一个老生常谈的问题了,今天我们就来一些看一下装箱和拆箱中的若干问题.本文先讲述装箱和拆箱最基本的东西,再来看一下面试笔试中经常遇到的与装箱 ...
- (转)深入剖析Java中的装箱和拆箱
转:https://www.cnblogs.com/dolphin0520/p/3780005.html 深入剖析Java中的装箱和拆箱 自动装箱和拆箱问题是Java中一个老生常谈的问题了,今天我们就 ...
- 深入剖析Java中的装箱和拆箱(转)
自动装箱和拆箱问题是Java中一个老生常谈的问题了,今天我们就来一些看一下装箱和拆箱中的若干问题.本文先讲述装箱和拆箱最基本的东西,再来看一下面试笔试中经常遇到的与装箱.拆箱相关的问题. 以下是本文的 ...
- Java基础——深入剖析Java中的装箱和拆箱
(转自:http://www.cnblogs.com/dolphin0520/p/3780005.html) 自动装箱和拆箱问题是Java中一个老生常谈的问题了,今天我们就来一些看一下装箱和拆箱中的若 ...
- java语法糖3 深入剖析Java中的装箱和拆箱
装箱 在Java SE5之前,如果要生成一个数值为10的Integer对象,必须这样进行: Integer i = new Integer(10); 而在从Java SE5开始就提供了自动装箱的特性, ...
随机推荐
- 软考高级及杭州E类人才申请经验分享
目录 前沿 软考高项 什么是软考 软考的基本过程 报名 是否报班 高项考些什么以及需要哪些书 如何准备 杭州E类人才申请 如何申请 大概的流程 前沿 挺久没更新了,自从成为房奴后,看书的时间就变少了, ...
- StackExchange.Redis 实现SetNx
今天有同事指出如何在StackExchange.Redis 实现Redis的原生命令. ConnectionMultiplexer redis = ConnectionMultiplexer.Conn ...
- POJ3368题解
题目大意:一个非降序序列,有若干查询,每次查询一个区间中重复次数最多的数字的个数. 思路:因为是非降序的,所以可以从头遍历把每个相同的数字划为一个块,用p[i]表示ai划分到了哪个块里面,同时还可以记 ...
- MySQL 学习笔记(二)MVCC 机制
之前在讲 MySQL 事务隔离性提到过,对于写操作给读操作的影响这种情形下发生的脏读.不可重复读.虚读问题.是通过MVCC 机制来进行解决的,那么MVCC到底是如何实现的,其内部原理是怎样的呢?我们要 ...
- 修改Ehcache缓存中取到的值,缓存中的值也被修改了
问题现象 我们从Ehcache中取出缓存的对象,之后将对象中的属性进行了修改使用.等再次从缓存中拿到对象后,发现对象的值变成了上一次调用修改后的对象了. 原因 Ehcache中缓存的是原对象的引用,所 ...
- 面向对象编程(C++篇1)——引言
目录 1. 概述 2. 详论 2.1. 类与对象 2.2. 数据类型 3. 目录 1. 概述 现代C++与最原始的版本已经差不多是两种不同的语言了.不断发展的C++标准给C++这门语言带来了更多的范式 ...
- appium滚动查找屏幕外的控件
嗯,还是把自己做的实验保存一下 Appium1.12.1+python2.7 实验滚动,查找屏幕外控件以及控制seekbar scroll() 是根据页面中两个元素位置之间的距离进行滑动. 滑动寻找屏 ...
- VirtualBox虚拟机--桥接模式
问题概述:VirtualBox虚拟机设置桥接模式,与宿主机互相ping通. 注:如果按照以下方式设置了还是ping不通,查看虚拟机防火墙是否已关. 公司电脑拿去维修了,在自己家里电脑上部署项目开发环境 ...
- tp6微信公众号开发者模式基础消息
官方文档 https://developers.weixin.qq.com/doc/offiaccount/Message_Management/Receiving_standard_messages ...
- java下载镜像
镜像地址 https://repo.huaweicloud.com/java/jdk/ 如果你不知道选择哪个版本就点击下面这个链接吧 https://repo.huaweicloud.com/java ...