浅析Java中的装箱和拆箱
来源:互联网 发布:业绩查询系统源码 编辑:程序博客网 时间:2024/05/17 02:53
毕业了,辞了成都的工作到深圳重新开始找,笔试时发现蛮多题考装箱拆箱知识的,这里简单总结一下。
什么是装箱和拆箱
要想弄懂这两个概念,首先要明白,Java中有基本类型
和包装类型
之分。
基本类型:int 、char、float 、double等
包装类型:Integer、String、Float、Double等
装箱就是把基本类型转换为对应的包装类型
拆箱就是把包装类型转换为基本类型
public class Test { public static void main(String[] args) { Integer a=10; //装箱 int b=a; //拆箱 }}
实现原理
我们反编译下上面的代码:
从2:
和7:
可以看出,Integer这个包装类,装箱和拆箱时分别用了valueOf()
和intValue()
这两个方法。
即上面的代码可以表示为:
public class Test { public static void main(String[] args) { Integer a=Integer.valueOf(10); //装箱 int b =a.intValue(); //拆箱 }}
笔试题
除了Integer,Float、Double等其余包装类也都是使用valueOf()
进行装箱,xxxValue()
进行拆箱。
接下来,我们来点笔试题,来进一步了解”装箱拆箱”的细节。
1. Integer类型的缓存内部类
public class Test { public static void main(String[] args) { Integer a1=100; Integer a2=100; Integer b1=200; Integer b2=200; Integer c1=new Integer(100); Integer c2=new Integer(100); System.out.println(a1==a2); System.out.println(b1==b2); System.out.println(c1==c2); }}
输出结果是:
true
false
false
c1==c2为false因为内存地址不一样,那a1==a2为true、b1==b2却为false是怎么回事?
这里很容易迷惑,若装箱后生成的Integer类型全为重新new的对象,那比较时应为false,但为何比较100时为true呢?
答案是Integer的缓存机制。类似于String的字符串池一样,为了提高Integer的内存利用率,Integer类中有一个静态内部类IntegerCache
。里面已经创建了-128~127的Integer对象。
所以装箱的-128~127的Integer指向的为同一个已经创建好的Integer对象。
我们看看源码就清楚了:
[-128,127]范围内的,直接返回的Integer内部缓存类中的“固定”对象,而超过了则重新创建。
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); }
接下来是Integer缓存类源码,其实就是Integer的静态内部类:
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() {} }
2. 运算符对装拆箱的影响
我们再来通过一段代码了解运算符对装拆箱的影响
Integer a=1; Integer b=2; Long c=2L; Integer d=new Integer(1); Integer e=new Integer(2); System.out.println(b.equals(c)); System.out.println(d==e); System.out.println(3L==a+b); System.out.println(e==1+new Integer(1));
输出结果是:
false
false
true
true
这段代码的结果说明如下几个知识点:
- 包装类的equals方法只比较同类型的类
不同的类即使数值相等也会返回false。所以b.equals(c)
会输出false。以Long的equals方法源码为例:
public boolean equals(Object obj) { if (obj instanceof Long) { return value == ((Long)obj).longValue(); } return false; }
- “+-*/”运算符会触发包装类的拆箱,“==”对于非对象比较数值
对于3l==a+b
,首先a和b会进行拆箱,然后相加,然后提升类型,进行数值比较,结果为true。
对于d==e
,由于比较的是两个对象,所以比较地址,为false。
对于e==1+new Integer(1)
,先是右边拆箱,相加,此时由于“==”比较的是数值与对象,所以对象会进行拆箱,最后比较数值,为true。
如果有疑问,可以自己反编译下,结果会很清晰。
3. 其余包装类的装拆箱
再简单补充下其余包装类装拆箱的特点
- Integer、Short、Byte、Character、Long这几个类的valueOf方法的实现是类似的。它们都有对应的[-128,127]的缓存内部类。
- Double、Float的valueOf方法的实现是类似的。没有缓存内部类。仔细想一下也会知道为什么,[-128,127]区间内的浮点数数目是无穷的,无法缓存下来提高效率。
- Boolean比较特别,它的
TRUE
和FALSE
其实是两个final的静态成员变量。所以valueOf方法返回的总是这两个变量。
用代码来验证一下:
Long a=50L; Long b=50L; Long aa=500L; Long bb=500L; System.out.println(a==b); System.out.println(aa==bb); System.out.println("---------分割线---------"); Double c=50.5; Double d=50.5; Double cc=500.5; Double dd=500.5; System.out.println(c==d); System.out.println(cc==dd); System.out.println("---------分割线---------"); Boolean e=true; boolean f=true; System.out.println(e==f);
输出结果:
true
false
———分割线———
false
false
———分割线———
true
本文部分内容参照如下文章作的总结:
深入剖析Java中的装箱和拆箱
- 浅析Java中的装箱和拆箱
- 浅析Java中的装箱和拆箱
- 【浅析java中的自动装箱和拆箱操作】浅析java中的自动装箱和拆箱操作
- Java中的自动装箱和拆箱
- java中的装箱和拆箱
- Java中的拆箱和装箱
- Java中的装箱和拆箱理解
- Java中的自动装箱和拆箱
- Java中的装箱和拆箱
- java中的自动装箱和拆箱
- java中的拆箱和自动装箱
- Java中的装箱和拆箱
- java中的自动拆箱和装箱
- New2011_装箱和拆箱 浅析深入
- Java中的装箱拆箱
- [java 数值]深入剖析Java中的装箱和拆箱
- Java基础:深入剖析Java中的装箱和拆箱
- Java中的包装类 装箱和拆箱
- [IMX6DL]fastboot erase SD分区实现
- GMap.net地图下载器
- 深入研究SSL【第二章 part-1】-SSL握手协议的研究
- 15 个 Android 通用流行框架大全
- linux命令 ls
- 浅析Java中的装箱和拆箱
- js高性能循环
- hdu 5444 Elven Postman
- android java.lang.IllegalStateException: Circular dependencies cannot exist in RelativeLayout
- Firebug控制台调试程序
- @NotNull、@NotEmpty、@NotBlank的区别
- Printers(一) 打印机配置信息
- 飞机大战整理
- 深入研究SSL【第二章 part-2】-SSL握手协议的研究