当前版本:jdk1.8
1. 声明
当前内容主要为复习三目运算符中的内容,当前思考主要来源于《Java开发手册(泰山版)》灵魂13问 书籍中的三目运算,本人由于对其看的不是很懂,所以觉得从字节码方面入手可以解决该问题,顺便归纳总结一下
2. 基本问题出现
public class OperationTest {
public static void main(String[] args) {
}
private static void test8() {
boolean flag = true;
boolean simpleBoolean = false;
Boolean objectBoolean = true;
Boolean nullBoolean = null;
Boolean x6 = flag ? simpleBoolean : nullBoolean;
}
private static void test7() {
boolean flag = true;
boolean simpleBoolean = false;
Boolean objectBoolean = true;
Boolean nullBoolean = null;
Boolean x6 = flag ? nullBoolean : simpleBoolean;
}
private static void test6() {
boolean flag = false;
boolean simpleBoolean = false;
Boolean nullBoolean = null;
Boolean x = flag ? nullBoolean: simpleBoolean;
}
private static void test5() {
boolean flag = false;
boolean simpleBoolean = false;
Boolean nullBoolean = null;
Boolean x = flag ? simpleBoolean : nullBoolean;
}
private static void test4() {
boolean flag = true;
boolean simpleBoolean = false;
Boolean nullBoolean = null;
boolean x = flag ? simpleBoolean : nullBoolean;
}
private static void test3() {
boolean flag = true;
boolean simpleBoolean = false;
Boolean nullBoolean = null;
boolean x = flag ? nullBoolean : simpleBoolean;
}
private static void test2() {
boolean flag = false;
boolean simpleBoolean = false;
Boolean nullBoolean = null;
boolean x = flag ? simpleBoolean : nullBoolean;
}
private static void test1() {
boolean flag = false;
boolean simpleBoolean = false;
Boolean nullBoolean = null;
boolean x = flag ? nullBoolean : simpleBoolean;
}
}
测试上面的用例得到的结果如下
表达式 | 结果 |
---|
boolean x = false ? null : false | 不报错 | boolean x = false ? false : null | 异常 | boolean x = true ? null : false | 异常 | boolean x = true ? false : null | 不报错 | Boolean x = false ? false : null | 异常 | Boolean x = false ? null : false | 不报错 | Boolean x = true ? null : false | 异常 | Boolean x = true ? false : null | 不报错 |
对于上面的表格可能看起来不是容易理解,所以本人决定使用字节码解析方式得到规律
3.字节码解析和查看并得到总结
private static void test1();
descriptor: ()V
flags: ACC_PRIVATE, ACC_STATIC
Code:
stack=1, locals=4, args_size=0
0: iconst_0
1: istore_0
2: iconst_0
3: istore_1
4: aconst_null
5: astore_2
6: iload_0
7: ifeq 17
10: aload_2
11: invokevirtual #28 // Method java/lang/Boolean.booleanValue:()Z
14: goto 18
17: iload_1
18: istore_3
19: return
从解析第一个test1可以发现当前只有一个拆箱的操作,并没有其他(可以发现1-4都是最多只有拆箱操作)
private static void test5();
descriptor: ()V
flags: ACC_PRIVATE, ACC_STATIC
Code:
stack=1, locals=4, args_size=0
0: iconst_0
1: istore_0
2: iconst_0
3: istore_1
4: aconst_null
5: astore_2
6: iload_0
7: ifeq 14
10: iload_1
11: goto 18
14: aload_2
15: invokevirtual #28 // Method java/lang/Boolean.booleanValue:()Z
18: invokestatic #22 // Method java/lang/Boolean.valueOf:(Z)Ljava/lang/Boolean;
21: astore_3
22: return
从test5中可以得到这里一般都会有装箱操作,且可能会有拆箱操作(5-8是基本差不多的)
于是得到汇总图
表达式 | 结果 | 拆装箱 |
---|
boolean x = false ? null : false | 不报错 | ((false没有拆箱;true有拆箱操作) | boolean x = false ? false : null | 异常 | (false有拆箱操作;true没有拆箱操作) | boolean x = true ? null : false | 异常 | (ture有拆箱操作;false没有拆箱操作) | boolean x = true ? false : null | 不报错 | (true没有拆箱操作,false才会有拆箱操作) | Boolean x = false ? false : null | 异常 | (false导致先拆箱后装箱;true导致进行装箱操作) | Boolean x = false ? null : false | 不报错 | (false导致装箱操作;true导致先拆箱后装箱) | Boolean x = true ? null : false | 异常 | (true导致先拆箱后装箱;false导致装箱操作) | Boolean x = true ? false : null | 不报错 | (true导致装箱操作;false导致先拆箱后装箱) |
4. jdk1.8中的总结
1. 当最左边的类型为基本类型的时候 ,且右边的表达式中存在包装和基本类型时,对于包装类型只会出现拆箱操作
2. 当最左边的类型为包装类型的时候 ,且右边的表达式中存在包装和基本类型时,对于包装类型进行拆箱然后装箱 ,对于基本类型只会装箱
所以对于以下
Map<String,Boolean> map = new HashMap<String, Boolean>();
Boolean b = (map!=null ? map.get("Hollis") : false);
由于最左边为包装 ,且flag为true右边存在基本类型和包装类型,且map.get("Hollis") 得到的为包装类型 ,所以必定会出现先拆箱然后装箱 ,此时map.get(“Hollis”)为null.所以直接报空指针异常
|