java自动装箱拆箱总结
对于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()方法将原始类 ...
随机推荐
- Asp.net Core2.0 缓存 MemoryCache 和 Redis
自从使用Asp.net Core2.0 以来,不停摸索,查阅资料,这方面的资料是真的少,因此,在前人的基础上,摸索出了Asp.net Core2.0 缓存 MemoryCache 和 Redis的用法 ...
- springboot AOP全局拦截日志记录
@Aspect@Component@Slf4jpublic class WebLogAspect { @Pointcut("execution(public * com.we.control ...
- [BZOJ]1017 魔兽地图DotR(JSOI2008)
BZOJ第一页做着做着就能碰到毒题,做到BZOJ1082小C就忍了,没想到下一题就是这种东西.这种题目不拖出来枭首示众怎么对得起小C流逝的青春啊. Description DotR (Defense ...
- ZhuSuan 是建立在Tensorflow上的贝叶斯深层学习的 python 库
ZhuSuan 是建立在Tensorflow上的贝叶斯深层学习的 python 库. 与现有的主要针对监督任务设计的深度学习库不同,ZhuSuan 的特点是深入到贝叶斯推理中,从而支持各种生成模式:传 ...
- SQL Server 2008作业失败无法确定所有者是否有服务器访问权限
调用作业---错误提示内容 该作业失败. 无法确定所有者 WIN-3TH1KNIT12D\Administrator (拥有作业 Database_Backup.step1)是否有服务器访问权限 (原 ...
- Python里面 search0和 match0的区别?
这是正则表达式里面的函数: match()函数只检测RE是不是在string的开始位置匹配,search()会扫描整个string查找匹配: 也就是说match()只有在0位置匹配成功的话才有返回,如 ...
- java.lang.NumberFormatException: For input string: " "
原因:这个异常是说,在将字符串""转换为number的时候格式化错误.额,很简单的异常,以前我是写个方法,然后遍历对比不正确的数字或者用正则表达式之类的.现在发现一个很漂亮的方法, ...
- 分享一个二维码图片识别控制台程序Demo
怎么用NuGet和配置log4net就不介绍了,直接上代码(QRDecodeDemo.zip). (Visual Studio 2015 下的项目,用的.NET Framework 4.5.2) 吐槽 ...
- 毕业回馈-89c51之定时器/计数器(Timer/Count)
今天分享的是89c51系列单片机的内部资源定时器/计数器,在所有的嵌入式系统中都包含这两个内部功能. 首先先了解几个定时器/计数器相关的概念: •时钟周期:时钟周期 T 是时序中最小的时间单位,具体计 ...
- Dapper连接与事务的简单封装
增删改查方面,已经有Dapper.Extension这么强大的工具了,我也实在没啥好写的,就随手写了个看起来比较优雅的连接与事务的封装.在之后使用Dapper.Extension类库时,完全可以照搬进 ...