Java条件运算符?:结果类型

Java条件运算符?:结果类型,java,nullpointerexception,type-conversion,conditional-operator,Java,Nullpointerexception,Type Conversion,Conditional Operator,我对条件运算符有点困惑。考虑下面两条线: Float f1 = false? 1.0f: null; Float f2 = false? 1.0f: false? 1.0f: null; 为什么f1变为null,而第二条语句抛出NullPointerException Langspec-3.0第15.25段sais: 否则,第二个和第三个操作数分别为S1和S2类型。 设T1为将装箱转换应用于S1后产生的类型,并设 T2是将装箱转换应用于S2后产生的类型。类型 条件表达式是应用捕获转换的结果 (

我对条件运算符有点困惑。考虑下面两条线:

Float f1 = false? 1.0f: null;
Float f2 = false? 1.0f: false? 1.0f: null;
为什么f1变为null,而第二条语句抛出NullPointerException

Langspec-3.0第15.25段sais:

否则,第二个和第三个操作数分别为S1和S2类型。 设T1为将装箱转换应用于S1后产生的类型,并设 T2是将装箱转换应用于S2后产生的类型。类型 条件表达式是应用捕获转换的结果 (§5.1.10)至润滑油(T1、T2)(§15.12.2.7)

所以对于
false?1.0f:null
T1是浮点型,T2是null型。但是
lub(T1,T2)
的结果是什么?第15.12.2.7段太多了

顺便说一句,我在Windows上使用1.6.018


PS:我知道
Float f2=false?(浮动)1.0f:假?(浮动)1.0f:空
不会抛出NPE。

看起来JVM试图将第二个null解装箱到float,而不是float,因此出现NullPointerException。我自己打一次。我的理解是,第二个if执行此操作,因为第一个if的真实部分计算为浮点,而不是浮点


在仔细考虑之后,我认为这是Java告诉您正在做一些奇怪的事情的一种方式。只要不嵌套三元ifs,您就可以了:-)

当您尝试为原语分配null时,以下内容将抛出NPE

    float f1 = false ? 1.0f: null;
    Float f = false? new Float(1.0f): true ? null : 1.0f;
我相信这就是导致第二个声明中NPE的原因。因为第一个三元数返回一个浮点值作为true,所以它也尝试将false转换为浮点值

第一条语句不会转换为null,因为所需的结果是浮点

例如,这不会抛出NPE,因为它不再需要转换为原语

    float f1 = false ? 1.0f: null;
    Float f = false? new Float(1.0f): true ? null : 1.0f;

不同之处在于编译时表达式的静态类型:

总结 详细说明: 这是我从通读和从你得到的结果中回顾得出的理解。归根结底,f2内部条件的第三个操作数的类型为null类型,而f2外部条件的第三个操作数的类型被视为浮点类型

注意:重要的是要记住类型的确定和装箱/拆箱代码的插入是在编译时完成的。装箱/拆箱代码的实际执行在运行时完成

Float f1 = (false ? 1.0f : null);
Float f2 = (false ? 1.0f : (false ? 1.0f : null));
f1条件和f2内部条件:(false?1.0f:null)

f1条件和f2内部条件相同:(false?1.0f:null)。f1条件和f2内部条件中的操作数类型为:

type of second operand = float
type of third operand = null type (§4.1)
中的大多数规则都被忽略了,并且确实应用了此最终评估:

否则,第二个和第三个操作数分别为S1和S2类型。设T1为将装箱转换应用于S1时产生的类型,设T2为将装箱转换应用于S2时产生的类型。条件表达式的类型是将捕获转换()应用于lub(T1,T2)()的结果

因为对于f1,赋值是一个浮点引用变量,所以表达式的结果(null)被成功赋值

对于f2外部条件:(false?1.0f:[f2内部条件])

对于f2外部条件,类型为:

type of second operand = float
type of third operand = Float
请注意,与直接引用空文本()的f1/f2内部条件相比,操作数类型有所不同。由于有两种数字可转换类型的差异,此规则适用于:

  • 否则,如果第二个和第三个操作数的类型可转换为()数字类型,则有几种情况:

    • 否则,二进制数字提升()将应用于操作数类型,条件表达式的类型是第二个和第三个操作数的提升类型。请注意,二进制数字提升执行取消装箱转换()和值集转换()

由于对f2内部条件(null)的结果执行了取消装箱转换,因此引发了NullPointerException。

我认为重写代码可以更清楚地解释:

    float f = 1.0f;

    Float null_Float  = false?        f  : null;       // float + null  -> OK
    Float null_Float2 = false? (Float)f  : null_Float; // Float + Float -> OK
    Float npe         = false?        f  : null_Float; // float + Float -> NPE
因此,NPE是指当我们尝试执行以下操作时:

Float npe = false? 1.0f : (Float)null;
:)


编辑:事实上,仔细看,这个例子实际上是(三元运算符和包装整数类型)和(自动取消装箱null)拼图的混合。无论如何,我只能推荐看这段视频,它很有教育意义,也很有趣。

Wow-15.12.2.7看起来确实适合在睡前阅读。。。如果有帮助的话,谷歌搜索表明
lub()
代表“最小上界”。好吧,根据我的理解?:结果的类型是预先建立的,与条件的评估无关。那么false的类型是什么呢?1.0f:null,它被用作F2中的第三个值?如果是空类型,则F2不应为NPE。如果它是float,既不是,也不是float。如果是这样的话,那么为什么他没有得到编译器错误,并且被允许在运行时看到这个错误?是的,类型是预先建立的,但是我们谈论的是null,系统必须推导出类型。第二个if类型是float,而不是float。?:结果类型转换应该完全独立于后面的赋值,否?请注意,在仅打印表达式时也会出现同样的问题:System.out.println(false?1.0f:null);->空系统.out.println(false?1.0f:false?1.0f:null);->NPE我知道如何解决这个特殊情况,但我真的很想了解发生了什么,以避免在我的应用程序代码中出现NPE。如果为false?f1案例的1.0f:null工作正常,将导致null,为什么它不能作为f2表达式中的第三个值正常工作?因为它将它转换为浮点值,因为第一个三元值是浮点值