条件表达"? :"尽管分支返回不同类型,但编译

时间:2015-08-13 10:40:29

标签: java ternary-operator

我已经开始学习java了,而且我对以下条件表达式感到不满:

 ((1<2)?5:(3<4))

在我发现此示例的书中,它说它是语法错误,因为它无法将数值转换为布尔值。 相同页面后,有一个不同练习的测试,包括这一个。在eclipse中编写和编译后,它给出了输出5。 为什么?我已经阅读了有关此运算符的一些内容,并清楚地表明这两个表达式必须是布尔值或算术运算符,所以它是eclipse的一个问题吗?

8 个答案:

答案 0 :(得分:13)

当他们谈到编译器错误的情况时,就像这样

int a= ((1<2)?5:(3<4));

但是当(3&lt; 4)返回布尔值时,它不能分配给整数变量

但是当您只是System.out.println(((1<2)?5:(3<4)));时,它不必将值分配给任何变量,并使用方法System.out.println(Object)

打印输出值

如果你稍微更改一下表达式并执行: - System.out.println(((1>2)?5:(3<4)))那么它会打印true作为输出

答案 1 :(得分:11)

条件运算符有三个操作数 - 第一个是条件,第二个和第三个是分开的“分支”。评估哪个分支取决于条件是评估为真还是假。

在您的情况下,您有:

  • 条件:1 < 2
  • Branch1:5
  • Branch2:3 < 4

现在的问题是这里的两个分支是不同的类型,因此表达式没有有用的原始结果类型。它(令人惊讶的是,IMO)有效,整体表达类型为Object - 基本上,两个分支都涉及拳击。所以这个:

Object o = 1 < 2 ? 5 : 3 < 4;

相当于:

Object o = 1 < 2 ? (Integer) 5 : (Boolean) (3 < 4);

JLS 15.25中指定 - 您的情况显示在“表15.25-B。条件表达式类型(原始第3操作数,第II部分)”中,表示当第三个操作数的类型为{{1}时第二种类型为boolean,结果为int - 基本上为lub(Integer,Boolean)

现在没关系:

Object

这样:

int x = 1 < 2 ? 5 : 4; // Both branches are of type int

...但您当前的情况有一个类型为// Very confusing with all these conditions, but valid! boolean y = 1 < 2 ? 5 < 6 : 3 < 4; // Both branches are of type boolean 的分支,另一个类型为int

答案 2 :(得分:2)

唯一的问题&#34;这个三元运算符就是它返回不同的类型。

让我们用伪代码中的if条件打开它:

((1<2)?5:(3<4))

if (1 < 2) {
    // returns int
    return 5;
}
else {
    // either returns boolean (true)
    if (3 < 4) {
        return true;
    }
    else {
        return false;
    }
}

因此表达式在某些条件下可能有效。

例如,Object o = ((1<2)?5:(3<4));编译正常(3 < 4部分有警告),因为Object可以从原始boolean和{{1}中加框}。

答案 3 :(得分:2)

如果您将其传递给System.out.println(),则不会抱怨,因为所有值都会转换为字符串。

所以,

System.out.println((1<2) ? 5 : (3<4));
//Will print 5

System.out.println((3<2) ? 5 : (3<4));
//Will print true

但是,

int i = ((3<2) ? 5 : (3<4));

boolean b = ((3<2) ? 5 : (3<4));

将导致编译错误。

答案 4 :(得分:2)

由于在a?b:c表达式中,bc的类型可能不同,因此Java编译器必须尝试推断表达式的返回类型,以查找类型这适合两个操作数。

这是通过查看类型树并找到最近的共同祖先来完成的。对于参考类型,在最坏的情况下,这个最接近的共同祖先是Object(1 > 2) ? new StringBuilder() : new ArrayList();将返回类型为Object,因此,如果您要将其分配给Object类型的变量(或将其传递给期望参数为Object的方法()),没关系。否则,您将收到编译错误,因为无法保证结果可以转换为任何其他类型。

您的方案稍微复杂一点的地方在于它将基元定义为bcintboolean。这些必须首先自动装箱到IntegerBoolean,然后上述过程正常运行,返回类型为Object。但是,如果您要将Object分配给int,那将无法正常工作,因此int x = ((1<2)?5:(3<4));无法编译,但Object x = ((1<2)?5:(3<4));有效。< / p>

注意:在实践中,由于可能存在多个不相关的共同祖先,但这并没有改变基本原则。

答案 5 :(得分:0)

?是一个三元运算符,详见JSL (§15.25)

variable = condition ? value if true : value if false;

示例

String isFalse = 3 < 4 ? "true" : "false";  // false
String isTrue  = 3 == 3 ? "true" : "false";  // true

条件表达式的类型确定如下:

  • 如果第二个和第三个操作数具有相同的类型(可能是null类型),那么这就是条件表达式的类型。

  • 如果第二个和第三个操作数之一是原始类型T,而另一个操作数的类型是将装箱转换(第5.1.7节)应用于T的结果,那么条件表达式的类型是吨。

  • 如果第二个和第三个操作数之一是null类型而另一个操作数的类型是引用类型,则条件表达式的类型是该引用类型。

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

现在,了解这一点并翻译你的表达:

((1<2)?5:(3<4))

您获得1<2=false3<4=false

false ? 5 : false

因此,如果您尝试分配变量

boolean var = false ? 5 : false
int     var = false ? 5 : false

您将遇到语法错误,因为它无法将数值转换为布尔值

Type mismatch: cannot convert from Object&Comparable<?>&Serializable to int<br>
                                   ↑ (3<4)                              ↑ variable assigned

答案 6 :(得分:0)

以下编译并正确运行,无论xy的值是多少。你得到数字5或布尔值true。没有问题,因为结果未在任何地方分配(或者结果是Object传递给println(Object o))。

    int x = 1;
    int y = 2;
    System.out.println(x<y ? 5 : 3<4);

问题来自于作业。

    int x = 1;
    int y = 2;
    int a = x<y ? 5 : 3<4;  // Won't compile without a cast to int, if x > y, results in a `ClassCastException`.

因此,虽然结果可能有不同的类型,但它不一定是个好主意。它们都需要可以赋值给结果,所以无论从任何一个语句返回什么,以下内容总是有效。

Object o = x < y ? "String object" : new ArrayList();  // Works since the return type is compatible

答案 7 :(得分:0)

3&lt; 4将返回布尔值。不是int。

1&lt; 2?是的,然后打印5 但是,如果你要改变&#34;&lt;&#34;到&#34;&gt;&#34;你会得到&#34; true&#34;。