x2编译时类型为X,运行时类型为Y. 这意味着,当编译器需要推理时,x2它会假设它x2是一个X. 但是在运行时, 的行为x2将是 a的行为Y。
所以让我们更详细地解释一下。这是不合法的:
x2.do2();
这是因为编译器认为那x2是一个X并且X没有一个名为的方法do2,只有Y。编译器不知道那x2是 a Y,它只知道编译时类型x2是 a X。
但是,这将是合法的,并且不会导致运行时异常:
((Y)x2).do2();
我们告诉编译器,看,我知道的比你多x2;我知道它是一个Y,所以只需发出调用Y.do2withx2作为接收器的指令。
此外,假设我们有一个接受Ys 的方法:
void M(Y y) { }
那么这将是不合法的:
M(x2);
同样,这是因为编译器认为它x2是 a X,不是所有X的 s 都是Ys,所以它必须拒绝方法调用。
但是,这将是合法的,并且不会导致运行时异常:
M((Y)x2);
再一次,我们告诉编译器,看,我知道的比你知道的多x2;我知道它是 a ,所以请相信我,并像aY一样调用该方法。x2Y
让我们进一步假设我们有一个在 中定义X并被覆盖的方法Y:
class X {
void do1() {}
void N() { System.out.println("X");
}
class Y extends X { void do2() {}
@Override
void N() { System.out.println("Y");
}
现在如果我们说:
x2.N();
我们将看到Y打印到控制台。这是因为运行时类型x2是Y.
所有这些都是人们在谈到多态性时所要表达的意思的一部分。
使用两个构造函数创建对象是否合法。
此语句中没有两个构造函数:
X x2 = new Y();
只有一个构造函数。左侧是变量声明。它声明了一个名为x2type的变量X。右侧是构造函数调用。我们正在调用 ; 的公共无参数构造函数Y。这将创建一个新的Y. 整个语句是一个赋值语句。我们将右侧的结果分配给左侧的变量。赋值是合法的,因为所有Y的 s 也是多态X的,因为Y extends X.