1

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.

c0der
  • 18,467
  • 6
  • 33
  • 65

2 Answers2

2

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());
    }
}
Oliver Dain
  • 9,617
  • 3
  • 35
  • 48
  • `BClass` does pass `BContent` to the `AClass` constructor, or am I missing something ? – c0der Feb 18 '17 at 07:36
  • You pass it to AClass but then you duplicate and hide it by also copying it to a property in BClass with the same name. – Oliver Dain Feb 18 '17 at 08:09
  • In the answer above **only** AClass has a reference to `content` – Oliver Dain Feb 18 '17 at 08:10
  • `BClass` references `content` by `System.out.println("BClass content is "+ content.getValue());` which causes `NullPointerException` because it has not been initialized. – c0der Feb 18 '17 at 08:39
  • Yup. But since AClass is its parent it can access it from the parent. And, since the parent gets initialized before the children you'll be safe. Have you tried the suggestion here and found that it doesn't work? – Oliver Dain Feb 18 '17 at 08:51
0

Based on @Oliver Dain answer I ended up with :

 class AClass <T extends AContent>{

        private T content;

        AClass(T content) {

            this.content = content;
            print();
        }

        protected void print() {

            System.out.println("Content is "+ getContent().getValue());
        }

        public T getContent() {
            return content;
        }
    }

class BClass extends AClass<AContent> {

    BClass(BContent content) {
        super(content);
    }

    public static void main(String[] args) {

        new BClass(new BContent());
    }
}

class AContent {

    int getValue() {
        return 1;
    }
}

class BContent extends AContent{

    @Override
    int getValue() {
        return 2;
    }
}
c0der
  • 18,467
  • 6
  • 33
  • 65