有如下代码:
class Random {
public static void main(String[] args) {
boolean f = true; // false
var randomClass = f ? new A() : new B();
randomClass.randomMethod();
}
}
class A {
public void randomMethod() {
System.out.println("Method in class A");
}
}
class B {
public void randomMethod() {
System.out.println("Method in class B");
}
}
根据我的假设,它应该根据 f 初始化变量 randomClass 作为类 A 或 B 实例的引用变量。但实际上,上面的代码甚至无法编译。无论 f 的值如何,类型推断都会为变量 randomClass 分配一个引用,该引用不是对类 A 或 B 的实例,而是对类 Object 的实例。由于 randomMethod() 方法未在 Object 中定义,因此代码本身无法编译。
为什么会发生这种情况?从逻辑的角度来看,三元运算符应该等同于以下表示法:
if (f) {
var randomClass = new A();
} else {
var randomClass = new B();
}
也就是说,根据 f,randomClass 必须引用类 A 的实例或类 B 的实例。
我不需要关于如何在不使用三元运算符的情况下实现此目的的替代解决方案。需要解释为什么三元运算符会产生这样的结果。
var- 这是语法糖。事实上,编译器必须创建一个这种类型的变量,其中既可以放置类A,也可以放置类B。通常在这种情况下,使用所有对象的祖父母Object。这就是你所观察到的。您在这里可以做的是描述包含它的接口
randomMethod并从中继承两个类。并且在调用该方法之前,将变量转换randomClass为该接口。仍然不可能将接口写入变量;它仍然在变量中Object。那么,要么使用此方法为您的对象创建一个基类,然后将基类对象放入一个变量中。
三元运算符等价于以下表示法
在这里您可以看到,必须首先将变量指定为类型。由于类型不同,两个类的公共类型将是
Object操作符
var v = b?foo:bar;实际上返回到和 的
T最具体的泛型类型在哪里。foobar在您的情况下,一般类型是 y
A和BthisObject。您总是将编译程序的过程与执行程序的过程混淆。 “无论 f 的值如何,类型推断都会分配” - 这里值在运行时解析,类型推断在编译时发生。
“也就是说,根据 f,randomClass 必须引用 A 类的实例或 B 类的实例。” - 这是指执行期间。但编译器如何知道这一点呢?
其余的在其他答案中有解释。