Java抽象类不寻常的行为
抽象类:
public abstract class ParentClass {
private static ParentClass mpParentClass;
public ParentClass() {
mpParentClass = this;
}
public abstract void method1();
public static ParentClass getInstance() {
return mpParentClass;
}
}
儿童班:
public class ChildClass extends ParentClass{
@Override
public void method1() {
System.out.print("ChildClass class method");
}
}
测试等级:
public class TestClass {
public static void main(String[] args) {
ChildClass cl = new ChildClass();
ParentClass.getInstance().method1();
}
}
在这里我创建了一个抽象类和一个扩展父抽象类的Child类。
父类抽象类持有对其自身实例的引用,并通过静态方法返回该实例。
在Test类中,如果我不创建ChildClass的对象,则java抛出NullPointerException。
但是在创建ChildClass的对象之后,然后查询ParentClass的实例并调用抽象方法之后,它会调用由ChildClass实现的方法。
我无法理解这种行为。 请任何人解释。
当你第一次实例化一个ChildClass时,你使用parentClass的默认构造函数来实例化具有ChildClass类型的私有字段。 如果你不这样做,私有字段mpParentClass不是实例化的。 所以你有一个NullPointerException
ParentClass.getInstance()
是一个静态方法,所以它不需要你的类的一个实例运行。
通过调用此方法,您将返回静态成员mpParentClass
。 但默认情况下,这个成员包含一个null
引用。
因此,如果不做任何事情,确实会导致NullPointerException
因为您没有调用ParentClass
的构造函数。
在你的例子中,你首先创建一个ChildClass
的实例。
这将调用该类的默认构造函数。 这个默认构造函数具有调用超类的默认构造函数的标准行为(通过调用super()
)。
因此,通过实例化ChildClass
您可以调用ParentClass
的构造函数,它将mpParentClass
项设置为此。 这里指的是你正在创建的ChildClass
的实例。
所以在构建之后, mpParentClass
将包含新创建的ChildClass
实例。
这是发生了什么。
当您为ChildClass
调用构造函数时,隐含的是该方法中的第一个实际调用是针对超类构造函数的。 如果您有一个需要/允许备用参数的超类构造函数,则可以手动调用它。 但它发生在你身上。
当调用超类构造函数时,将为该新实例分配一个static
引用,该实例是一个ChildClass
实例。 (因为这是this
是在这种情况下)。
如果您打电话给:
new ChildClass();
new ParentClass() {
public void method1() {
System.out.println("Anonymous class!");
}
};
ParentClass.getInstance().method1();
你会看到"Anonymous class!"
,因为每次创建ParentClass
实现的任何实例时都会重新分配一个静态引用。
关于你的NullPointerException
- mpParentClass
分配给一个值的唯一地方是在ParentClass
的构造函数中。 如果您从不创建ParentClass
的实例,那么将永远不会调用此代码,并且mpParentClass
将保留其原始值(该值为null
。 尝试调用方法或访问null
引用上的属性会产生NullPointerException
。
要问的问题是:如果你从来没有实例化任何实现(通过'调用'它们的构造函数),你期望mpParentClass
变量被设置mpParentClass
,如果不是null
?