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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2615498/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-29 22:01:41  来源:igfitidea点击:

Java conditional operator ?: result type

javanullpointerexceptiontype-conversionconditional-operator

提问by Wangnick

I'm a bit puzzled about the conditional operator. Consider the following two lines:

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

Float f1 = false? 1.0f: null;
Float f2 = false? 1.0f: false? 1.0f: null;

Why does f1 become null and the second statement throws a NullPointerException?

为什么 f1 变为 null 并且第二个语句抛出 NullPointerException?

Langspec-3.0 para 15.25 sais:

Langspec-3.0 第 15.25 段说:

Otherwise, the second and third operands are of types S1 and S2 respectively. Let T1 be the type that results from applying boxing conversion to S1, and let T2 be the type that results from applying boxing conversion to S2. The type of the conditional expression is the result of applying capture conversion (§5.1.10) to lub(T1, T2) (§15.12.2.7).

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

So for false?1.0f:nullT1 is Float and T2 is the null type. But what is the result of lub(T1,T2)? This para 15.12.2.7 is just a bit too much ...

所以对于false?1.0f:nullT1 是 Fl​​oat 并且 T2 是空类型。但结果是lub(T1,T2)什么呢?这一段 15.12.2.7 有点太多了......

BTW, I'm using 1.6.0_18 on Windows.

顺便说一句,我在 Windows 上使用 1.6.0_18。

PS: I know that Float f2 = false? (Float) 1.0f: false? (Float) 1.0f: null;doesn't throw NPE.

PS:我知道这Float f2 = false? (Float) 1.0f: false? (Float) 1.0f: null;不会引发 NPE。

采纳答案by Bert F

The difference is static typing of the expressions at compile time:

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

Summary

概括

E1: `(false ? 1.0f : null)`
    - arg 2 '1.0f'           : type float,
    - arg 3 'null'           : type null 
    - therefore operator ?:  : type Float (see explanation below)
    - therefore autobox arg2
    - therefore autobox arg3

E2: `(false ? 1.0f : (false ? 1.0f : null))`
    - arg 2 '1.0f'                    : type float
    - arg 3 '(false ? 1.0f : null)'   : type Float (this expr is same as E1)
    - therefore, outer operator ?:    : type float (see explanation below)
    - therefore un-autobox arg3

Detailed Explanation:

详细说明:

Here's my understand from reading through the specand working backwards from the result you got. It comes down to the type of the third operand of the f2 innerconditional is null type while the type of the third operand of the f2 outerconditional is deemed to be Float.

这是我通过阅读规范和从你得到的结果向后工作的理解。归结为 f2内部条件的第三个操作数的类型是 null 类型,而 f2外部条件的第三个操作数的类型被认为是 Float。

Note:Its important to remember that the determination of type and the insertion of boxing/unboxing code is done at compile-time. Actual execution of boxing/unboxing code is done at run-time.

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

Float f1 = (false ? 1.0f : null);
Float f2 = (false ? 1.0f : (false ? 1.0f : null));

The f1 conditional and the f2 inner conditional: (false ? 1.0f : null)

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

The f1 conditional and the f2 inner conditional are identical: (false ? 1.0f : null). The operand types in the f1 conditional and the f2 inner conditional are:

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

type of second operand = float
type of third operand = null type (§4.1)

Most of the rules in §15.25are passed up and this final evaluation is indeed applied:

§15.25中的大部分规则都被通过了,并且确实应用了这个最终评估:

Otherwise, the second and third operands are of types S1 and S2 respectively. Let T1 be the type that results from applying boxing conversion to S1, and let T2 be the type that results from applying boxing conversion to S2. The type of the conditional expression is the result of applying capture conversion (§5.1.10) to lub(T1, T2) (§15.12.2.7).

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

S1 = float
S2 = null type
T1 = Float
T2 = null type
type of the f1 and f2 inner conditional expressions = Float

Since for f1, the assignment is to a Float reference variable, the result of the expression (null) is successfully assigned.

由于对于 f1,赋值是给一个 Float 引用变量,表达式 (null) 的结果赋值成功。

For f2 outer conditional: (false ? 1.0f : [f2 inner conditional])

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

For the f2 outer conditional, the types are:

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

type of second operand = float
type of third operand = Float

Note the difference in operand types compared to the f1/f2 inner conditionals that reference the nullliteral directly (§4.1). Because of this difference of having 2 numeric-convertible types, this rule from §15.12.2.7applies:

请注意,与直接引用文字的 f1/f2 内部条件相比,操作数类型的差异(第4.1 节)。由于具有 2 个数字可转换类型的差异,第15.12.2.7 节中的这条规则适用:

  • Otherwise, if the second and third operands have types that are convertible (§5.1.8) to numeric types, then there are several cases: ...

    • Otherwise, binary numeric promotion (§5.6.2) is applied to the operand types, and the type of the conditional expression is the promoted type of the second and third operands. Note that binary numeric promotion performs unboxing conversion(§5.1.8) and value set conversion (§5.1.13).
  • 否则,如果第二个和第三个操作数具有可转换(第5.1.8 节)为数字类型的类型,则有几种情况:...

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

Because of the unboxing conversion performed on the result of the f2 inner conditional (null), a NullPointerException is raised.

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

回答by JRL

I think rewriting the code makes the explanation clearer:

我认为重写代码使解释更清楚:

    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

Thus the NPE is when we try to do something like:

因此,NPE 是当我们尝试执行以下操作时:

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

回答by kloffy

To be or not to be, that is the question.:)

成为或不成为,这是个问题。:)

Edit:Actually, looking closer it seems that this case is actually a mix between the Hamlet(ternary operator and wrapped integral types) and the Elvis(auto-unboxing null) puzzlers. In any case, I can only recommend watching the video, it is very educational and enjoyable.

编辑:实际上,仔细观察似乎这种情况实际上是哈姆雷特(三元运算符和包装的整数类型)和猫王(自动拆箱空值)谜题的混合。无论如何,我只能推荐观看视频,它非常有教育意义和乐趣。

回答by objects

The following will throw a NPE as you attempt assign a null to a primitive

当您尝试为原语分配空值时,以下内容将引发 NPE

    float f1 = false ? 1.0f: null;

That I believe is whats causing the NPE in the second statement. Because the first ternary returns a float for true it attempts to convert the false to a float as well.

我认为这就是第二个声明中导致 NPE 的原因。因为第一个三元返回一个浮点数为真,它也尝试将假转换为浮点数。

The first statement will not convert to null as the required result is a Float

第一个语句不会转换为 null,因为所需的结果是一个 Float

This for example this would not throw a NPE as its no longer needs to convert to primitive

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

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

回答by Slava Imeshev

It looks like the JVM tries to unbox the second null to floatinstead of Float, thus NullPointerException. Hit it myself once. My take is that the second ifdoes it because the truepart of the first ifevaluates as a float, not a Float.

看起来 JVM 试图将第二个 null 拆箱为float而不是Float,因此 NullPointerException 。自己打过一次。我的看法是第二个if这样做是因为第一个if真实部分评估为浮点数,而不是浮点数。

After giving it a second thought, I think this a way of Java telling you that you are doing something strange. Just don't nest ternary ifs and you will be fine :-)

再三考虑之后,我认为这是 Java 告诉您您正在做一些奇怪的事情的一种方式。只是不要嵌套三元 ifs,你会没事的:-)