Java抽象类异常行为

时间:2015-08-21 12:21:04

标签: java oop inheritance abstract-class abstract

抽象类:

   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实现的方法。

我无法理解这种行为。请有人解释一下。

6 个答案:

答案 0 :(得分:3)

第一次实例化ChildClass时,使用parentClass的默认构造函数,该构造函数使用ChildClass类型实例化私有字段。如果不这样做,私有字段mpParentClass不会实例化。所以你有一个NullPointerException

答案 1 :(得分:3)

ParentClass.getInstance()是一种静态方法,因此它不需要运行类的实例。

通过调用此方法,您将返回静态成员mpParentClass。 但默认情况下,此成员包含null引用。

因此,如果没有做任何事情,这确实会导致NullPointerException,因为您没有调用ParentClass的构造函数。

在您的示例中,您首先要创建ChildClass

的实例

这将调用该类的默认构造函数。这个默认构造函数具有调用超类的默认构造函数的标准行为(通过调用super())。

因此,通过实例化ChildClass,您调用ParentClass的构造函数,将mpParentClass数据库设置为此。这里指的是您正在创建的ChildClass的实例。

因此,构造mpParentClass将包含新创建的ChildClass实例。

答案 2 :(得分:0)

这里发生了什么。

当您调用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变量为什么设置为,如果不是null

答案 3 :(得分:0)

父类是抽象的,因此您无法直接使用构造函数。默认情况下,静态变量实例为null,这会导致您的NullPointerException。设置此变量的唯一方法是调用构造函数,该构造函数仅在调用子类的构造函数时调用。

答案 4 :(得分:0)

这是因为您只分配到mpParentClass构造函数中的静态字段ParentClass。因此,在创建ChildClass的实例之前,mpParentClass为空。在您的示例中,在创建派生类ParentClass的实例时,将隐式调用基类ChildClass构造函数。

我建议你改用singleton pattern吗?

public class Singleton {
  // Private constructor prevents instantiation from other classes
  private Singleton() {}

 /**
   * SingletonHolder is loaded on the first execution of Singleton.getInstance() 
   * or the first access to SingletonHolder.INSTANCE, not before.
   */
  private static class SingletonHolder { 
    private static final Singleton INSTANCE = new Singleton();
  }

  public static Singleton getInstance() {
    return SingletonHolder.INSTANCE;
  }
}

答案 5 :(得分:-1)

您正在创建ChildClass,然后通过不必要的诡计调用其method1()

您确实意识到this将是ChildClass构造函数中的ParentClass实例,对吧?它必须是,因为父类是抽象的,因此永远不会有一个代表它的this实例。