考虑以下代码类。
public class A
{
public A()
{
callCreation();
}
protected void callCreation()
{
System.out.println("A Created!!");
}
}
public class B extends A
{
protected void callCreation()
{
System.out.println("B Created!!");
}
}
public class C extends B
{
protected void callCreation()
{
System.out.println("C Created!!");
}
public static void main(String[] args)
{
A a = new A();
A b = new B();
A c = new C();
}
}
下面给出了运行C类的输出。
A Created!! B Created!! C Created!!
输出
A Created!!中的第一个输出行,因为当调用类A的构造函数时,它会在调用callCreation之前隐式调用超类的构造函数(java.lang.Object)( )类A的构造函数中的方法。这也是B和C类的情况。在那种情况下,当调用B的构造函数时,调用流程通常应该是:B的构造函数 - > A的构造函数 - > java.lang.Object的构造函数 - >回到A的callCreation()方法来完成调用A的构造函数。如果是这样,如何打印被覆盖的值而不是超级类的值?所以问题是'什么时候创建了一个类的对象?换句话说,只有在构造函数完成调用/初始化其自身内的所有元素之后,才应创建类的对象。如果是这样,如何从子类调用方法而不是从父类调用?
答案 0 :(得分:4)
B和C中的callCreation
方法覆盖来自A的方法。因此,当在构造函数A中调用该方法时,将运行B和C中的实现,即使B和C的构造函数尚未执行。这是可能的,因为构造函数实际上并不创建对象,而是在JVM创建它之后的某些时刻调用初始化。
一般来说,调用可以从构造函数中重写的方法是一个非常糟糕的主意。 B或C中的方法可以假定构造函数和对象初始值设定项已经运行,并从字段中读取意外值。例如,以下内容最终会打印"B Created!! null"
,因为该字段仍未分配其值。
public class B extends A
{
final String msg = "Yes!";
protected void callCreation()
{
System.out.println("B Created!! "+msg);
}
}
答案 1 :(得分:1)
公共类A {
public A() {
this.callCreation();
}
protected void callCreation() {
System.out.println("A Created!!");
}
}
B类延伸A {
public B() {
super();
}
protected void callCreation() {
System.out.println("B Created!!");
}
}
C类延伸B {
public C() {
super();
}
protected void callCreation() {
System.out.println("C Created!!");
}
public static void main(String[] args) {
A a = new A();
A b = new B();
A c = new C();
}
}