关于Java嵌套三目运算符的返回值类型

1. 问题

result = exp1 ? value1 : exp2 ? value2 : value3;

上述表达式中result的类型是什么?

2. 解答

  1. 前置知识:
    1. 浮点型大于整形,Double大于Float,Long大于Integer,Integer大于Short,Short大于Byte(大于是指不同类型变量计算时返回大的类型)
    2. 整数默认类型为Integer、浮点数默认类型为Double
    3. 基本类型和包装类型混用时,包装类型会自动拆箱为基本类型
  2. 分类讨论:
    1. 当且仅当value1、value2和value3为相同的包装类型时,返回值类型为包装类型;若不同,根据规则1,返回值类型为相应的基本类型
    2. char和Character在和其他数值类型的变量运算中,总是隐式的转换为int类型
    3. 当value1、value2和value3中包含String、boolean、Boolean类型值,且不含reference类型值时,返回值类型为Serializable类型
    4. 当value1、value2和value3中存在reference类型时,返回值为Object类型

3. 意义

  1. 自动拆箱时,有可能发生NullPointException,需要谨慎使用三目运算符的嵌套形式:
    • flag ? 1 : null这样的用法是没有问题的,该表达式的返回值是Integer类型
    • flag1 ? 1 : flag2 ? 2 : null,当flag1和flag2均为false时,会发生NullPointException
      • 因为该表达式的返回值类型为int,是基本类型,而null不是基本类型,所以需要自动拆箱将值赋给返回值,而“null.intValue()”当然会导致发生NullPointException
      • 即使使用Integer类型的变量去接该返回值,同样还是会发生NullPointException,因为该表达式的返回值类型是确定的(int类型),使用Integer类型接返回值时,只不过是隐式的使用了自动装箱,而自动装箱之前的自动拆箱过程仍是有异常的

4. 代码

public class Test { 
    private static void test(boolean flag1, boolean flag2) { 
        Double d = flag1 ? new Double(1d) : flag2 ? new Double(2d) : new Double(3d);
        Float f = flag1 ? new Float(1f) : flag2 ? new Float(2f) : new Float(3f);
        Long l = flag1 ? new Long(1L) : flag2 ? new Long(2L) : new Long(3L);
        Integer i = flag1 ? new Integer(1) : flag2 ? new Integer(2) : new Integer(3);
        Short s = flag1 ? new Short((short) 1) : flag2 ? new Short((short) 2) : new Short((short) 3);
        Character c = flag1 ? new Character('1') : flag2 ? new Character('2') : new Character('3');
        Byte by = flag1 ? new Byte((byte) 1) : flag2 ? new Byte((byte) 2) : new Byte((byte) 3);
        Boolean bo = flag1 ? new Boolean(true) : flag2 ? new Boolean(true) : new Boolean(false);

        double d1 = flag1 ? new Integer(1) : flag2 ? new Integer(2) : new Double(3.0);
        float f1 = flag1 ? new Integer(1) : flag2 ? new Long(2) : new Float(3.0);
        long l1 = flag1 ? new Integer(1) : flag2 ? new Integer(2) : new Long(3);
        int i1 = flag1 ? new Integer("1") : flag2 ? new Byte("2") : new Short("3");
        short s1 = flag1 ? new Byte("1") : flag2 ? new Byte("3") : new Short("4");
        char c1 = flag1 ? '1' : flag2 ? '2' : new Character('3');
        byte by1 = flag1 ? new Byte("1") : flag2 ? new Byte("2") : (byte) 3;
        boolean bo1 = flag1 ? false : flag2 ? false : new Boolean(true);
        
        int i2 = flag1 ? new Short("1") : flag2 ? new Byte("2") : new Character('3');

        Serializable serializable1 = flag1 ? 1 : flag2 ? 3.3 : "hello";
        Serializable serializable2 = flag1 ? 1 : flag2 ? 3.3 : false;
        Serializable serializable3 = flag1 ? 1 : flag2 ? 3.3 : Boolean.TRUE;
        
        Object o = flag1 ? 1 : flag2 ? new Object() : "hello";
    }
}

5. 字节码

// java文件
public class Test { 
    public static void main(String[] args) { 
        // 基本类型接返回值
        int res = false ? 1 : false ? 2 : null;
    }
}

// 字节码文件
0 aconst_null
1 checkcast #2 <java/lang/Integer>
4 invokevirtual #3 <java/lang/Integer.intValue : ()I> // 自动拆箱
7 istore_1
8 return
// java文件
public class Test { 
    public static void main(String[] args) { 
        // 包装类型接返回值
        Integer res = false ? 1 : false ? 2 : null;
    }
}

// 字节码文件
0 aconst_null
1 checkcast #2 <java/lang/Integer>
4 invokevirtual #3 <java/lang/Integer.intValue : ()I> // 自动拆箱
7 invokestatic #4 <java/lang/Integer.valueOf : (I)Ljava/lang/Integer;> // 自动装箱
10 astore_1
11 return

从上面字节码可以看出,用包装类型去接返回值,是在自动拆箱后多了一步自动装箱

    原文作者:死灵镜面
    原文地址: https://blog.csdn.net/adminhyh/article/details/124395876
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞