具有不同类型表达式的三元运算符[重复]

Posted

技术标签:

【中文标题】具有不同类型表达式的三元运算符[重复]【英文标题】:Ternary operator with different types of expressions [duplicate] 【发布时间】:2021-12-18 10:40:09 【问题描述】:

我在玩三元运算符时发现了一些奇怪的东西。我有以下代码:

class Main 

  static void foo(int a)
    System.out.println("int");
  

  static void foo(String a)
    System.out.println("String");
  

  static void foo(Object a)
    System.out.println("object");
  

  public static void main(String[] args) 
    foo(2==3 ? 0xF00:"bar");
    System.out.println((2==3 ? 0xF00:"bar").getClass().getName());
  

结果

对象

java.lang.String

第一行结果表明该指令以对象参数传递给foo方法。

指令本身产生String的第二行。

问题:

    为什么如果结果是 String 编译器决定使用 Object?

    这是因为类型不明确吗?

    如果是,那么为什么返回类名java.lang.String

【问题讨论】:

您混淆了运行时和编译时类型。 (Object)"foo" 的类型在编译时为Object,在运行时为String (2==3 ? 0xF00:"bar") 产生字符串(“bar”),然后getClass() on println(a) 添加到foo(Object),它将打印String“栏”。 【参考方案1】:

如果对阅读不感兴趣,可以跳到摘要。

请参阅此处的 JavaDoc:https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.25

低于 15.25.3。参考条件表达式上面写着:

条件表达式的类型是 应用捕获转换的结果

捕获转换:https://docs.oracle.com/javase/specs/jls/se8/html/jls-5.html#jls-5.1.10

总结:

对于类型确定,使用捕获转换,其中对于您的示例,首先将 int 装箱为 Integer,然后获取最接近的 Integer 和 String 的公共超类,即 Object 类。所以条件表达式的类型是Object,所以会调用以Object为参数的方法。

现在对于第二部分,首先评估条件运算符,然后将其拆箱,然后评估 .getClass()。所以它会打印 java.lang.String。

这也记录在这里:https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.25

15.25 岁以下。条件运算符 ? :

在运行时,条件的第一个操作数表达式 首先计算表达式。如有必要,拆箱转换是 对结果执行。

【讨论】:

【参考方案2】:

在Java 中,您有编译时间 类型信息和运行时间 类型信息。编译时类型信息是编译器可以通过查看值或表达式的类型推断出它,而不是执行它。当编译器看到表达式时

2 == 3 ? 0xF00 : "bar"

它不知道2 == 3 是真还是假,因为它不执行代码。所以它只知道结果可以是Integer,或String。因此,当需要选择调用哪个foo 方法时,它会选择接受Object 的方法,因为它知道在这两种情况下都可以使用的唯一方法。

但是,当代码实际运行时,2 == 3 将为 false,结果将是一个String,其getClass() 方法将返回String.class。这就是您需要注意的:getClass() 不会返回变量在编译时所具有的类型,而是返回变量在运行时所拥有的对象的实际类型。即

Object o = "Hello!";
System.out.println(o.getClass());

将打印java.lang.String,因为即使对于编译器来说它是一个Object,在运行时它实际上是一个String

【讨论】:

【参考方案3】:

在编译阶段,编译器注意到2 == 3 ? 0xF00 : "bar" 的结果可能是int 或String。为了兼容两者,它决定调用foo(Object a)

在运行时,2 == 3 ? 0xF00 : "bar" 的结果是 String bar

【讨论】:

int 先装箱。

以上是关于具有不同类型表达式的三元运算符[重复]的主要内容,如果未能解决你的问题,请参考以下文章

三元运算符

Kotlin三元运算符[重复]

如何在不重复自己的情况下编写三元运算符(又名 if)表达式

三元运算符的两个右手表达式必须是兼容的类型吗?

Java连载18-引用数据类型三元运算符控制语句if

三元运算符