对于java1.5引入的自动装箱拆箱,之前只是知道一点点,最近在看一篇博客时发现自己对自动装箱拆箱这个特性了解的太少了,所以今天研究了下这个特性。以下是结合测试代码进行的总结。
测试代码:
int a = 1;
Integer b = 1;
Integer c = 1;
Integer d = 2;
Integer e = 3;
Integer f = 128;
Integer g = 128;
Long h = 3L;
Double m = 4.0;
Double n = 4.0;
Float p = 5f;
Float q = 5f;
System.out.println("a == b : " + (a == b)); //true
System.out.println("b ==c : " + (b == c)); //true
System.out.println("e == (c + d) : " + (e == (c + d))); //true
System.out.println("e.equals(c + d) : " + (e.equals(c + d))); //true
System.out.println("h == (c + d) : " + (h == (c + d))); //true
System.out.println("h.equals(c + d) : " + (h.equals(c + d))); //false
System.out.println("f == g : " + (f == g)); //false
System.out.println("m == n : " + (m == n)); //false
System.out.println("p == q : " + (p == q)); //false
System.out.println("m == d * 2 : " + (m == d * 2)); //true
System.out.println("p == (d + e) : " + (p == (d + e))); //true
测试输出结果与说明:
1. a == b : true
当基本类型包装类与基本类型值进行==运算时,包装类会自动拆箱。即比较的是基本类型值。
具体实现上,是调用了Integer.intValue()方法实现拆箱。
可以在测试代码处打断点,使用F5快捷键step
into至每一步执行方法,会看到调用了Integer.intValue()方法实现了拆箱。
2. b == c : true
b和c类型均为Integer包装类,故对基本类型进行自动装箱后赋值给b和c。
在进行==运算时不会触发拆箱操作。所以比较的是引用地址,说明b和c是同一个对象。
java中自动装箱调用的是Integer.valueOf()方法实现的,可以像例1一样打断点验证。
为什么b和c 会是同一个对象呢?查看Integer.valueOf()方法实现即可知道,如下:
下面的代码中可以看到,对于-128至127这256个值,直接获取的IntegerCache中的值。
而IntegerCache是Integer中的一个静态内部类,
里面将-128至127(即一个字节所能表示的所有带符号值 -2^7至2^7-1)的包装类存在了一个数组中。
对于-128到127之间的数,直接从数组中获取,其他的数则使用new生成。所以此处输出true。
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++);
}
3. e == (c + d) : true
包装类在执行加减乘除求余等运算时,会触发拆箱操作,故c、d拆箱后相加,
结果为基本类型;然后e与基本类型进行==运算,触发拆箱操作。
4. e.equals(c + d) : true
首先,c + d 拆箱运算得到基本类型值;然后当进行equals运算时,
会触发基本类型值的装箱操作,c + d 的结果会自动装箱为包装类;最后与e进行equals运算。
5. h == (c + d) : true
运算顺序与上面例3中一致,唯一区别是h自动拆箱是调用了Long.longValue()实现。
6. h.equals(c + d) : false
运算顺序与上面例4中一致,为false的原因在于c + d的运算结果自动装箱后类型为Integer,
而h的类型为Long,类型不一样,equals的结果为false。
7. f == g : false
请参考上面例2中的解释。
超出了-128至127的缓存范围,故在valueOf()方法中使用new生成了新对象。
8. m == n : false
p == q : false
与上面例子1、2中的结果不同,对于Boolean、Byte、Character、Short、Integer、Long六种基本类型,
对于一个字节以内的值-128到127(Boolean只有true和false)都实现了缓存机制。
不在此范围的数才在对应的valueOf()方法中new出一个新的对象。
但是对于Double和Float类型的浮点数据,在-128到127之间除了256个整数外还有无数的小数,
故java中没有实现Double和Float中一些数的缓存。
所以,对于Double和Float的自动装箱,都是new出新的对象。故此两例均输出false。
10. m == d * 2 : true
p == (d + e) : true
请参考例3和例5。
反编译后代码:
使用java反编译工具,对class字节码文件进行反编译,结果如下所示。从下面的反编译代码,我们可以看到java是如何实现自动装箱、拆箱的。
int a = 1;
Integer b = Integer.valueOf(1);
Integer c = Integer.valueOf(1);
Integer d = Integer.valueOf(2);
Integer e = Integer.valueOf(3);
Integer f = Integer.valueOf(128);
Integer g = Integer.valueOf(128);
Long h = Long.valueOf(3L);
Double m = Double.valueOf(4.0D);
Double n = Double.valueOf(4.0D);
Float p = Float.valueOf(5.0F);
Float q = Float.valueOf(5.0F);
System.out.println("a == b : " + (a == b.intValue()));
System.out.println("b ==c : " + (b == c));
System.out.println("e == (c + d) : " + (e.intValue() == c.intValue() + d.intValue()));
System.out.println("e.equals(c + d) : " + e.equals(Integer.valueOf(c.intValue() + d.intValue())));
System.out.println("h == (c + d) : " + (h.longValue() == c.intValue() + d.intValue()));
System.out.println("h.equals(c + d) : " + h.equals(Integer.valueOf(c.intValue() + d.intValue())));
System.out.println("f == g : " + (f == g));
System.out.println("m == n : " + (m == n));
System.out.println("p == q : " + (p == q));
System.out.println("m == d * 2 : " + (m.doubleValue() == d.intValue() * 2));
System.out.println("p == (d + e) : " + (p.floatValue() == d.intValue() + e.intValue()));
参考文章:
①Java 自动装箱和拆箱
②Java自动装箱与拆箱及其陷阱
③深入剖析Java中的装箱和拆箱
④四道Java基础题 你能对几道?
java自动装箱拆箱总结的更多相关文章
-
JAVA自动装箱拆箱与常量池
java 自动装箱与拆箱 这个是jdk1.5以后才引入的新的内容,作为秉承发表是最好的记忆,毅然决定还是用一篇博客来代替我的记忆: java语言规范中说道:在许多情况下包装与解包装是由编译器自行完成的 ...
-
Java 自动装箱/拆箱
自动装箱/拆箱大大方便了基本类型(8个基本类型)数据和它们包装类的使用 自动装箱 : 基本类型自动转为包装类(int >> Integer) 自动拆箱: 包装类自动转为基本类型(Integ ...
-
Java自动装箱拆箱
一.装箱.拆箱定义 如果一个int型量被传递到需要一个Integer对象的地方,那么,编译器将在幕后插入一个对Integer构造方法的调用,这就叫做自动装箱.而如果一个Integer对象被放到需要in ...
-
深入理解Java自动装箱拆箱机制
1.自动装箱与拆箱的定义 装箱就是自动将基本数据类型转换为包装器类型(int-->Integer): 拆箱就是自动将包装器类型转换为基本数据类型(Integer-->int). Java中 ...
-
那些年一起踩过的坑 — java 自动装箱拆箱问题
坑在哪里? 我们都知道Java的八种基本数据类型:int, short, long, double, byte, char, float, boolean 分别有各自对应的包装类型:Integ ...
-
Java 的自动装箱拆箱
Java 是面向对象的语言,其基本数据类型也就有了相对应的类,称为包装类.以下是基本数据类型对应的包装类: 基本数据类型 包装类 byte(1字节) Byte short(2字节) Short int ...
-
Java八种基本数据类型的大小,以及封装类,自动装箱/拆箱的用法?
参考:http://blog.csdn.net/mazhimazh/article/details/16799925 1. Java八种基本数据类型的大小,以及封装类,自动装箱/拆箱的用法? 原始类型 ...
-
java基础1.5版后新特性 自动装箱拆箱 Date SimpleDateFormat Calendar.getInstance()获得一个日历对象 抽象不要生成对象 get set add System.arrayCopy()用于集合等的扩容
8种基本数据类型的8种包装类 byte Byte short Short int Integer long Long float Float double Double char Character ...
-
Java的自动装箱/拆箱
概述 自JDK1.5开始, 引入了自动装箱/拆箱这一语法糖, 它使程序员的代码变得更加简洁, 不再需要进行显式转换.基本类型与包装类型在某些操作符的作用下, 包装类型调用valueOf()方法将原始类 ...
随机推荐
-
Working with Data &#187; Getting started with ASP.NET Core and Entity Framework Core using Visual Studio &#187; 增、查、改、删操作
Create, Read, Update, and Delete operations¶ 5 of 5 people found this helpful By Tom Dykstra The Con ...
-
Query for Component Path within PeopleSoft Portal
1) Run the below SQL to get the content reference name for your component ;-- Replace :1 with the c ...
-
js 设置 获取css样式
先看一段代码,为了体现一会下面说的js用style获取css样式的不同 一:给div设置margin-left(用style设置css样式没什么问题) box.style.marginLeft=&qu ...
-
创建BDC(Business Data Connectivity Service)
创建Business Data Connectivity http://blog.csdn.net/spfarm/article/details/44015915 创建和使用Business Data ...
-
svg图片转换为WEB字体图标
今天我学会了使用字*作网站 icomoon.io 制作web文本图标.跟我一起学习吧! (1)字*作网站 icomoon.io 点击 icomoon APP ---> imp ...
-
WPF 实现阴影效果
一.WPF最常见的一个阴影效果的类是DropShadowEffect.它有几种比较有用的属性比如:Color设置颜色Direction设置投影的方向ShadowDepth设置投影距纹理下方的距离Opa ...
-
fhq treap抄袭笔记
目录 碎碎念 点一下 注意!!! 模板 fhq treap 碎碎念 我咋感觉合并这么像左偏树呢 ps:难道你们的treap都是小头堆的吗 fhq真的是神人 现在看以前学的splay是有点恶心,尤其是压 ...
-
.NET4.5新特性async和await修饰符实现异步编程
开篇 每一个版本的.net都会引入一些新的特性,这些特性方便开发人员能够快速实现一些功能.虽然.net版本一直在更新,但是新版本对旧版本的程序都是兼容的,在这一点上微软做的还是非常好的.每次学一个新内 ...
-
POJ 3255 Roadblocks (次短路 SPFA )
题目链接 Description Bessie has moved to a small farm and sometimes enjoys returning to visit one of her ...
-
winform网络编程之TcpClient类,TcpListener类和UdpClient类
TcpClient类和TcpListener类 (1)TcpClient的用途: 用于在同步阻止模式下通过网络来链接.发送和接受流数据,在此情况下,必须有侦听此连接的请求,而侦听的任务就交给TcpLi ...