Search code examples
javainitializationfieldsubclassextending

Initializing sub class fields


Consider a simple AClass:

class AClass {

    private AContent content;

    AClass(AContent content) {

        this.content = content;
        print();
    }

    protected void print() {

        System.out.println("AClass content is "+ content.getValue());
    }
}

Where AContent is defined by:

class AContent {

    int getValue() {
        return 1;
    }
}

BClass, extends AClass, and is initialized by BContent which extends AContent as follows :

class BClass extends AClass {

    private BContent content;

    BClass(BContent content) {
        super(content);
        this.content = content;
    }

    @Override
    protected void print() {

        System.out.println("BClass content is "+ content.getValue());
    }
}

Where BContent is defined by:

class BContent extends AContent{

    @Override
    int getValue() {
        return 2;
    }
}

Constructing a BClass object :

public static void main(String[] args) {

        new BClass(new BContent());
}

Yields, as can be expected a NullPointerException caused by trying to print

System.out.println("BClass content is "+ content.getValue());

before content is initialized.
To overcome it, I thought about two options:
a.Remove print() invocation from the constructor. This will work but is not desirable for the functionality I need.
b.Make content static and use a static method to initialize it:

private static BContent content;

BClass(BContent content) {

  super(init(content));
}

private static BContent init(BContent content) {

    BClass.content = content;
    return content;
}

This will work, but looks quiet ugly.
I am seeking advice about how to better construct such code, to make it not only functional but also in line with common practices.


Solution

  • One way is to just pass BContent to the AClass constructor. That'll work since BContent is a subclass of AContent:

    class AClass {
        // Make protected so subclasses can access
        // (probably better via a protected get method)
        protected AContent content;
        ...
    }
    
    class BClass extends AClass {
    
        BClass(BContent content) {
            super(content);
        }
    
        @Override
        protected void print() {
            System.out.println("BClass content is "+ content.getValue());
        }
    }
    

    By the time your print method gets called content will have been initialized and you'll be OK.

    If you actually need BContent's type to be known in BClass use generics:

    class AClass<ContentT extends AContent> {
        // Make protected so subclasses can access
        // (probably better via a protected get method)
        protected ContentT content;
        ...
    }
    
    class BClass extends AClass<BContent> {
    
        BClass(BContent content) {
            super(content);
        }
    
        @Override
        protected void print() {
            // Now if I wanted I could do things with BContent that aren't
            // possible with AContent since the type of BContent is known
            System.out.println("BClass content is "+ content.getValue());
        }
    }