【问题标题】:Odd Java ternary behavior when assigning value. What is Java doing behind the scenes for this to happen?赋值时奇怪的 Java 三元行为。 Java 在幕后做了什么来实现这一点?
【发布时间】:2025-11-22 15:10:01
【问题描述】:

几天前,我遇到了一个令人着迷的场景,我找不到任何关于 Java 如何或为什么会发生以下情况的文档。 (这个 sn-p 只是 bug 的简化形式。)

    @Test
    public void test() {
      boolean bool = false;
      Integer intVal = Integer.valueOf(5);
      Long longVal = null;
      Long result = bool ? intVal : longVal;

      System.out.println(" > " + result);
   }

在上面的sn-p中:

如果 bool = true,则得到值 '5';

但如果 bool = false,则在尝试评估三元运算时会出现空指针异常。不是打印语句。


要解决这个问题,我只需将“结果”更改为

Long result = bool ? Long.valueOf(intVal) : longVal;

这样做会得到我需要的预期行为:

如果 bool = true,则得到值 '5';

但如果 bool = false,那么你会得到 'null'


现在有趣的部分是,如果你把它拆分成一个普通的 if/else 语句,那么 java 不会让你编译

longVal = intVal; 

但它没有通过三元运算符捕捉到这一点。那么 Java 做了什么来使它在原始的 sn-p 中成为 null 点呢?

(java 11)

【问题讨论】:

    标签: java nullpointerexception conditional-operator


    【解决方案1】:

    当你这样做时:

    Long result = bool ? intVal : longVal
    

    此表达式返回 long,当 bool 为 false 时,它​​会尝试将 null 拆箱为 Long 值以适应 result 变量并抛出 NPE。

    当你这样做时:

    Long result = bool ? Long.valueOf(intVal) : longVal
    

    这个表达式已经返回Long,那么不需要拆箱,null 值已成功分配给result 变量。

    参考:

    如 cmets 部分所述,为了更好地理解为什么会发生这种情况,请查看 JLS 的以下部分:

    【讨论】:

    • 我很惊讶你有不同的参考 table 15.25 A to E 很明显,整数/长整数会导致 bnp(整数,长整数)。
    • 好答案。一般来说,当我完全不知道里面发生了什么时,我建议查看编译后的字节码,它几乎准确地揭示了所描述的内容。至少在提取最小代码 sn-p 时,这或多或少是一个培训问题,如何阅读和理解它。
    • 正如JLS, Section 5.6.2 所说:“如果任何操作数是引用类型,它就会进行拆箱转换”;然后“应用扩展原始转换(§5.1.2)[..]”