Java:分析三目运算符的执行原理(jdk1.8基于字节码分析装箱拆箱问题)
Posted 你是小KS
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java:分析三目运算符的执行原理(jdk1.8基于字节码分析装箱拆箱问题)相关的知识,希望对你有一定的参考价值。
当前版本:jdk1.8
1. 声明
当前内容主要为复习三目运算符中的内容,当前思考主要来源于《Java开发手册(泰山版)》灵魂13问
书籍中的三目运算,本人由于对其看的不是很懂,所以觉得从字节码方面入手可以解决该问题,顺便归纳总结一下
2. 基本问题出现
public class OperationTest
public static void main(String[] args)
//test5();
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.所以直接报空指针异常
以上是关于Java:分析三目运算符的执行原理(jdk1.8基于字节码分析装箱拆箱问题)的主要内容,如果未能解决你的问题,请参考以下文章
Java中HashMap底层实现原理(JDK1.8)源码分析
Java中HashMap底层实现原理(JDK1.8)源码分析