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基于字节码分析装箱拆箱问题)的主要内容,如果未能解决你的问题,请参考以下文章

jdk1.8 HashMap扩容原理解析

Java中HashMap底层实现原理(JDK1.8)源码分析

Java中HashMap底层实现原理(JDK1.8)源码分析

Java中HashMap底层实现原理(JDK1.8)源码分析

JS中三目运算符和if else的区别分析与示例

java 三目运算符