Java - 三元运算符奇怪的行为
Java - ternary operator weird behaviour
我试图从 double
中删除 fractional
部分,以防它是完整的,使用:
(d % 1) == 0 ? d.intValue() : d
并遇到了以下我不理解的行为:
public static void main(String[] args) {
Double d = 5D;
System.out.println((d % 1) == 0); // true
System.out.println((d % 1) == 0 ? d.intValue() : "not whole"); // 5
System.out.println((d % 1) == 0 ? d.intValue() : d); // 5.0
}
正如您在第三行看到的那样,即使满足条件 (d % 1) == 0
,运算符也会选择 else
值 - 5.0
。
这是怎么回事?
选择正确。然后它把它包裹成双层。这是 3 个关键点:
如果第二个和第三个操作数的类型相同,就是条件表达式的类型。换句话说,您可以通过避开混合类型计算来避免整个混乱。
如果其中一个操作数是 T 类型,其中 T 是 byte 、 short 或 char ,而另一个操作数是 int 类型的常量表达式,其值可以用 T 类型表示,则条件表达式是 T.
否则,对操作数类型应用二进制数值提升,条件表达式的类型是第二个和第三个操作数的提升类型。
三元条件运算符的 return 类型必须使第 2 个和第 3 个操作数都可以分配给它。
因此,在您的第二种情况下,运算符的 return 类型是 Object
(因为 d.intValue()
和 "not whole"
都必须可以分配给它)而在第三种情况是 Double
(因为 d.intValue()
和 d
都必须可以分配给它)。
打印运行时类型为 Integer
的 Object
得到 5
而打印 Double
得到 5.0
.
表达式 a ? b : c
的类型始终与 c
相同或 b
和 c
的最近公共父级相同。
System.out.println((d % 1) == 0 ? d.intValue() : "not whole"); // Comparable a parent of Integer and String
System.out.println((d % 1) == 0 ? d.intValue() : d); // Double is a widened int
顺便说一句 d % 1
只会检查它是否是一个整体,而不是它是否足够小以适合 int
值。更安全的检查是在转换为 int
或 long
时查看值是否相同
double d = 5.0;
if ((long) d == d)
System.out.println((long) d);
else
System.out.println(d);
或者您可以通过
阻止 long
变回双倍
double d = 5.0;
System.out.println((long) d == d ? Long.toString((long) d) : Double.toString(d));
在你的例子中,三元运算符的第二个和第三个参数是类型 "int" 和 "Double"。 Java 必须将这些值转换为相同的类型,以便它们可以从三元运算符返回。 Java 语言规范中给出了这样做的规则。 https://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.25
在您的情况下,这些规则导致两个参数都转换为类型 "double"("Double" 未装箱,int 已值转换)。
解决方法是将参数转换为三元运算符,使它们属于同一类型(下面的括号可能比严格需要的要多,我对 java 运算符有点生疏优先规则)。
System.out.println((d % 1) == 0 ? ((Number)(d.intValue())) : (Number)d);
我试图从 double
中删除 fractional
部分,以防它是完整的,使用:
(d % 1) == 0 ? d.intValue() : d
并遇到了以下我不理解的行为:
public static void main(String[] args) {
Double d = 5D;
System.out.println((d % 1) == 0); // true
System.out.println((d % 1) == 0 ? d.intValue() : "not whole"); // 5
System.out.println((d % 1) == 0 ? d.intValue() : d); // 5.0
}
正如您在第三行看到的那样,即使满足条件 (d % 1) == 0
,运算符也会选择 else
值 - 5.0
。
这是怎么回事?
选择正确。然后它把它包裹成双层。这是 3 个关键点:
如果第二个和第三个操作数的类型相同,就是条件表达式的类型。换句话说,您可以通过避开混合类型计算来避免整个混乱。
如果其中一个操作数是 T 类型,其中 T 是 byte 、 short 或 char ,而另一个操作数是 int 类型的常量表达式,其值可以用 T 类型表示,则条件表达式是 T.
否则,对操作数类型应用二进制数值提升,条件表达式的类型是第二个和第三个操作数的提升类型。
三元条件运算符的 return 类型必须使第 2 个和第 3 个操作数都可以分配给它。
因此,在您的第二种情况下,运算符的 return 类型是 Object
(因为 d.intValue()
和 "not whole"
都必须可以分配给它)而在第三种情况是 Double
(因为 d.intValue()
和 d
都必须可以分配给它)。
打印运行时类型为 Integer
的 Object
得到 5
而打印 Double
得到 5.0
.
表达式 a ? b : c
的类型始终与 c
相同或 b
和 c
的最近公共父级相同。
System.out.println((d % 1) == 0 ? d.intValue() : "not whole"); // Comparable a parent of Integer and String
System.out.println((d % 1) == 0 ? d.intValue() : d); // Double is a widened int
顺便说一句 d % 1
只会检查它是否是一个整体,而不是它是否足够小以适合 int
值。更安全的检查是在转换为 int
或 long
double d = 5.0;
if ((long) d == d)
System.out.println((long) d);
else
System.out.println(d);
或者您可以通过
阻止long
变回双倍
double d = 5.0;
System.out.println((long) d == d ? Long.toString((long) d) : Double.toString(d));
在你的例子中,三元运算符的第二个和第三个参数是类型 "int" 和 "Double"。 Java 必须将这些值转换为相同的类型,以便它们可以从三元运算符返回。 Java 语言规范中给出了这样做的规则。 https://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.25
在您的情况下,这些规则导致两个参数都转换为类型 "double"("Double" 未装箱,int 已值转换)。
解决方法是将参数转换为三元运算符,使它们属于同一类型(下面的括号可能比严格需要的要多,我对 java 运算符有点生疏优先规则)。
System.out.println((d % 1) == 0 ? ((Number)(d.intValue())) : (Number)d);