Java中三元运算符的装箱拆箱

Java中三元运算符的装箱拆箱遇到的问题及其原因分析

Java中三元运算符的装箱拆箱

问题复现

测试环境中,有一段一直报NullPointerException的代码

//map.get(CommonConstants.COUNTRYID) != null  此处为false
//busiBasicinfo.getCountryId())此处为null
busiBasicinfoDTO.setCountryId(map.get(CommonConstants.COUNTRYID) != null ? Long.parseLong(map.get(CommonConstants.COUNTRYID)) :busiBasicinfo.getCountryId());

乍一看没有想明白为什么这样的一段这么简单的代码为什么会抛NullPointerException呢。 于是为了找出问题,在本地写了一个main方法,尝试复现问题。

public static void main(String[] args) {
    Long l1 = null;
    Long l2 = false ? Long.parseLong(null) : l1;
    System.out.println(l2);
}

果然,结果抛出了Exception in thread "main" java.lang.NullPointerException。 这个时候,直觉告诉我应该是三元运算符的自动装箱/拆箱的问题了。 用反编译工具反编译生成的jar包,得到反编译的源码如下:

 public static void main(String[] args)
  {
    Long l1 = null;
    Long l2 = Long.valueOf(l1.longValue());
    System.out.println(l2);
  }

这里可以明显的看到Long.valueOf(l1.longValue()),此处的l1.longValue()会抛出一个NullPointerException。 基本可以确定是三元运算符时自动装箱/拆箱的问题。

原因

[条件语句] ? [表达式1] : [表达式2] 当[表达式1]和[表达式2]的类型不相同时,那么他们需要 对交集类型的自动参考转换。 核心规则可以表达为以下三点:

  1. 如果表达式1和表达式2操作数具有相同的类型,那么它就是条件表达式的类型。
  2. 如果一个表达式的类型是byte、short、char类型的,而另外一个是int类型的常量表达式,且它的值可以用类型byte、short、char三者之一表示的,那么条件表达式的类型就是三者之一
  3. 否则,将对操作数类型进行二进制数字提升,而条件表达式的类型就是第二个和第三个操作数被提升之后的类型
public static void main(String[] args) {
        char ch = 'a';
        int num = 0 ;
        boolean bool = true;
        System.out.println( bool ? ch : 0);
        System.out.println( bool ? ch : num);
}

参照上面的结论,可以验证上述代码运行结果为:

a
97

参考资料

http://www.cnblogs.com/Lowp/archive/2012/09/03/2668154.html