Java自动装箱与拆箱
如果你看到这边,答案都正确,而且没有丝毫的疑问,那么对于你来说这篇博文就此结束了,如果没有,请继续翻阅。
首先从最基础的开始讲起,首先通过反编译来看一看自动装箱和拆箱的过程:
首先看如下一段程序:
0: iconst_1 1: invokestatic #2 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer; 4: astore_1 5: iconst_2 6: invokestatic #2 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer; 9: astore_2 10: aload_1 11: invokevirtual #3 // Method java/lang/Integer.intValue:()I 14: aload_2 15: invokevirtual #3 // Method java/lang/Integer.intValue:()I 18: iadd 19: invokestatic #2 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer; 22: astore_3 23: return LineNumberTable: line 8: 0 line 9: 5 line 10: 10 line 11: 23
可以看到Integer a=1实际上自动装箱为Integer a = Integer.valueOf(1),而在进行a+b的时候可以看到进行了自动拆箱,将a拆箱为Integer.intValue();然后将a和b的int值相加,相加之后有进行了自动装箱:Integer c=Integer.valueOf(3).
接下来我们就可以上面题目中给出的 System.out.println(c==d);和System.out.println(e==f);他们分别的结果为true和false。
知道Integer会缓存-128至127的朋友估计这两条语句的输出结果都能答对。
如果没有答对,请看解析:
Integer c=3;会自动装箱为Integer c = Integer.valueOf(3),那么看一下valueOf方法的源码:
if (i = IntegerCache.low i = IntegerCache.high) return IntegerCache.cache[i + (-IntegerCache.low)]; return new Integer(i); 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会缓存-128值127的内容,如果值在这个区间之内(比如c和d),那么就会返回IntegerCache中的引用,所以Integer c= Integer d = IntegerCache.cache[3+(–128)] = IntegerCache.cache[131], c和d是相等的。
但是如果超过这个区间,比如e和f,则Integer e = new Integer(321); Integer f = new Integer(321);new出来的自然是在堆中新开辟的内存,两份地址不同,自然e和f不同,也就是如果遇到这样的情况:
0: iconst_1 1: invokestatic #2 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer; 4: astore_1 5: iconst_2 6: invokestatic #2 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer; 9: astore_2 10: iconst_3 11: invokestatic #2 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer; 14: astore_3 15: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream; 18: aload_3 19: invokevirtual #4 // Method java/lang/Integer.intValue:()I 22: aload_1 23: invokevirtual #4 // Method java/lang/Integer.intValue:()I 26: aload_2 27: invokevirtual #4 // Method java/lang/Integer.intValue:()I 30: iadd 31: if_icmpne 38 34: iconst_1 35: goto 39 38: iconst_0 39: invokevirtual #5 // Method java/io/PrintStream.println:(Z)V 42: return
可以看到实际在c==(a+b)的时候是执行拆箱机制,实际上就是在运算3==2+1,当然就是true咯。
继续说明: System.out.println(c.equals(a+b));
同样看一下c.equals(a+b)反编译的结果(篇幅限制,只截取部分相关的结果):
27: iadd 28: invokestatic #2 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer; 31: invokevirtual #5 // Method java/lang/Integer.equals:(Ljava/lang/Object;)Z
可以看到a+b先拆箱为int再相加之后再装箱为Integer型与c进行equals比较,那么我们再看一下equals()方法的源码:
最后来看一下System.out.println(g==(a+b));和System.out.println(g.equals(a+b));两条语句。
System.out.println(g==(a+b));由前面的推论可知最后g拆箱为long型,a+b为int型,基础类型int可以自动升级为long,所以输出为true。
对于System.out.println(g.equals(a+b));可以看一下Long的equals()方法。
对于(a+b)来说是Integer类型,所以返回false.
鉴于包装类的“==”运算在不遇到算术运算的情况下不会自动拆箱,以及它们equals()方法不处理数据转型的关系,博主建议在实际编码中要尽量避免这样使用自动装箱与拆箱机制。
Java包装类,基本的装箱与拆箱 将原始类型和包装类分开以保持简单。当需要一个适合像面向对象编程的类型时就需要包装类。当希望数据类型变得简单时就使用原始类型。
Java中自动装箱和拆箱 装箱(Boxing),也称为包装(Wrapper),是在对象中放置原语类型(primitive type)的过程,以便原语(primitive)可以作为引用对象使用。 这里的`primitive type`就是Java里面的基本类型,所有的基本类型都有一个与之对应的类。例如,Integer类对应基本类型int。 通常,这些类称为包装器(wrapper)。这些对象包装器类拥有很明显的名字:Integer、Long、Float、Double、Short、Byte、Character、Void和Boolean(前6个类派生于公共的超类Number)。
相关文章
- java中functional interface的分类和使用
- java enum(枚举)使用详解 + 总结
- 详解Java线程的几种状态
- JAVA类和方法的注释自定义自动生成(IDEA)
- java 使用注解自动转换字典信息(自定义注解转换字典)
- JAVA之万物皆空
- 用java se写一个超市购物系统
- Java多线程 3 线程同步
- Java的自动递增和递减
- Java 位运算(移位、位与、或、异或、非)
- JAVA代码静态检测之PMD
- Java读写Windows共享文件夹 .
- java程序性能优化
- Java中的动态代理模式
- java实现后台自动发邮件功能
- Java实现超级玛丽,老程序员的国庆假期泡汤了!
- Java中核心注解的作用及其使用,了解Spring容器装载的过程和机制,自定义注解来实现自动配置项目依赖环境,包括mybatis、Dubbo、log4j、RabbitMQ、redis相关等自动配置