Java Abstract class Unusual behavior

Abstract Class:

   public abstract class ParentClass {
    private static ParentClass mpParentClass;

    public ParentClass() {
        mpParentClass = this;
    }

    public abstract void method1();

    public static ParentClass getInstance() {
        return mpParentClass;
    }
}

Child Class :

public class ChildClass extends ParentClass{
    @Override
    public void method1() {
        System.out.print("ChildClass class method");
    }
}

Test Class :

public class TestClass {
    public static void main(String[] args) {
         ChildClass cl = new ChildClass();
        ParentClass.getInstance().method1();
    }
}

Here I have created an abstract class and a Child class which extends the parent Abstract class.

Parent abstract class holds a reference to its own instance and returns the instance through a static method.

In Test class, if I don't create an object of ChildClass, java throws NullPointerException.

But after creating object of ChildClass, and then querying instance of ParentClass and invoking abstract method, it calls method implemented by ChildClass.

I am unable to understand this behavior . Please anyone explain.


The first time you Instantiate a ChildClass you use the default constructor of parentClass which instantiate the private field with the ChildClass type . If you don't do that, the private field mpParentClass is not instantiate. So you have a NullPointerException


ParentClass.getInstance() is a static method so it doesn't require an instance of your class to run.

By calling this method you will return the static member mpParentClass . But by default this member contains a null reference.

So without doing anything this will indeed result in a NullPointerException because you didn't call the constructor of ParentClass .


In your example you first make an instance of the ChildClass .

This will call the default constructor of that class. This default constructor has the standard behavior of calling the default constructor of the super class (by calling super() ).

So by instantiating the ChildClass you call the constructor of ParentClass that will set the mpParentClass datamember to this. And here this refers to the instance of the ChildClass you are creating.

So after construction mpParentClass will contain the newly created instance of the ChildClass .


Here's what's happening.

When you call the constructor for your ChildClass , it's implicit that the first actual call in that method is to the superclass constructor. If you had a superclass constructor that required/allowed alternate arguments, you could call it manually. But it's happening for you.

When the superclass constructor is called, a static reference is being assigned to that new instance, which is a ChildClass instance. (Because that's what this is, in this case.)

If you were to call:

new ChildClass();
new ParentClass() {
    public void method1() {
        System.out.println("Anonymous class!");
    }
};
ParentClass.getInstance().method1();

You would see "Anonymous class!" , because there is one static reference that is going to be reassigned every time you create any instance of a ParentClass implementation.

Regarding your NullPointerException - the only place where mpParentClass is assigned to a value is in the constructor for ParentClass . If you never create an instance of a ParentClass , then this code will never be called, and mpParentClass will be left with its original value, which is null . Attempting to call a method or access a property on a null reference is what produces a NullPointerException .

The question to ask is: If you never instantiate any of your implementations (by 'calling' their constructors), what do you expect the mpParentClass variable to be set to, if not null ?

链接地址: http://www.djcxy.com/p/96758.html

上一篇: 抽象工厂设计:用枚举代替

下一篇: Java抽象类不寻常的行为