java特性-自动装箱与解箱
3 Autoboxing and Unboxing 自动装箱与解箱
3.1 Converting Primitives to Wrapper Types
看一下代码
1 2 | int foo = 0; Integer integer = foo; |
反编译class文件看到
1 2 | int foo = 0; Integer integer = Integer.valueOf(foo); |
是编译器帮助做了类型转换,各原始类型分别与它wrapper之间对应
Number n = 0.0f;
上面的申明显示从float转到Float,再从Float转到Number
3.2 Converting Wrapper Types to Primitives
看一下代码
1 2 | Integer integer = 1; int i = integer; |
反编译class文件看到
1 2 | Integer integer = Integer.valueOf(1); int i = integer.intValue(); |
先装箱再解箱,从上代码可以看出,如果
1 2 | Integer integer = null; int i = integer.intValue(); |
那么这个代码必定报NullPointerException,所以在解箱的时候需特别注意这点
3.3 Incrementing and Decrementing Wrapper Types
看一下代码
1 2 3 4 | Integer counter = 1; while (counter<10) { System.out.printf("Iteration %d%n", counter++); } |
反编译class文件看到
1 2 3 4 5 6 7 | Object aobj[]; for(Integer counter = Integer.valueOf(1); counter.intValue() < 10; System.out.printf("Iteration %d%n", aobj)) { aobj = new Object[1]; counter = Integer.valueOf(counter.intValue() + 1); aobj[0] = counter; } |
在这里我们看到自增长运算符++在这里也是可以使用的,编译后实际上在在int上操作,然后再赋给counter
3.4 Boolean Versus boolean
看一下代码A
1 2 3 4 | Boolean case1 = true; Boolean case2 = true; boolean case3 = false; Boolean result = (case1 || case2) && case3; |
反编译class文件看到
1 2 3 4 | Boolean case1 = Boolean.valueOf(true); Boolean case2 = Boolean.valueOf(true); boolean case3 = false; Boolean result = Boolean.valueOf((case1.booleanValue() || case2.booleanValue()) && case3); |
在进行或运算和与运算的时候都用到了unboxing,然后再把结果autoboxing
For inquiring minds, primitives are boxed up to wrapper types in equality comparisons. For operators such as <, >=, and so forth, the wrapper types are unboxed to primitive types.
看一下代码B
1 2 3 4 5 6 7 | Integer i1 = 256; Integer i2 = 256; if (i1 == i2) { System.out.println("Equal!"); } else { System.out.println("Not equal!"); } |
在大多数的jvm里返回的是not equal,==运算符直接是对两个object intances的比较,不多内存地址,结果当然是not equal,当然也有少部分最优化的jvm可能会返回equal,如果优化的策略是创建一个instance实例
看一下代码C
1 2 3 4 5 6 7 | Integer i1 = 100; Integer i2 = 100; if (i1 == i2) { System.out.println("Equal!"); } else { System.out.println("Not equal!"); } |
返回结果是equal,记住int值在-127到127的范围里,这样的两个同int值的Integer对象jvm是只分配一个内存地址的
3.5 Conditionals and Unboxing
看一下代码A
1 2 3 4 | Boolean arriving = false; Boolean late = true; System.out.println(arriving ? (late ? "It's about time!" : "Hello!") : (late ? "Better hurry!" : "Goodbye")); |
反编译看
1 2 3 | Boolean arriving = Boolean.valueOf(false); Boolean late = Boolean.valueOf(true); System.out.println(arriving.booleanValue() ? late.booleanValue() ? "It's about time!" : "Hello!" : late.booleanValue() ? "Better hurry!" : "Goodbye"); |
输出是Better hurry!
看一下代码B
1 2 3 4 | String s = "hello"; StringBuffer sb = new StringBuffer("world"); boolean mutable = true; CharSequence cs = mutable ? sb : s; |
反编译看到
1 2 3 4 | String s = "hello"; StringBuffer sb = new StringBuffer("world"); boolean mutable = true; CharSequence cs = ((CharSequence) (mutable ? ((CharSequence) (sb)) : ((CharSequence) (s)))); |
现在的jdk中String和StringBuffer都实现了CharSequence,故String和StringBuffer都转成CharSequence
3.6 Method Overload Resolution
看一下代码
1 2 3 4 5 6 7 8 9 10 11 12 | public static void main(String[] args) { int foo = 1; doSomething(foo); } public static void doSomething(double num) { System.out.println("double called"); } public static void doSomething(Integer num) { System.out.println("Integer called"); } |
猜一下哪个被调用呢?
输入的结果是”double called”,在这里,你是不是会想到autoboxing?实际上在新的java中方法的调用遵循以下3个规则
1:不考虑boxing,unboxing及变参,而是先遵循1.4下的调用顺序
2:1.4下的规则找不到,参数boxing或者unboxing,找可调用的方法
3:以上规则找不到,考虑变参的方式调用方法