Cheok Yan Cheng
Cheok Yan Cheng

Reputation: 42670

Don’t call subclass methods from a superclass constructor

Consider the following code

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package example0;

/**
 *
 * @author yccheok
 */
public class Main {

    static class A {
        private final String var;

        public A() {
            var = getVar();
            // Null Pointer Exception.
            System.out.println("var string length is " + var.length());
        }

        public String getVar() {
            return "String from A";
        }
    }

    static class B extends A {
        private final String bString;

        // Before B ever constructed, A constructor will be called.
        // A is invoking a overriden getVar, which is trying to return
        // an initialized bString.
        public B() {                
            bString = "String from B";
        }

        @Override
        public String getVar() {
            return bString;
        }
    }

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        B b = new B();
    }

}

Currently, in my mind, there are two ways to avoid such problem.

Either making class A final class.

static final class A {
    private final String var;

    public A() {
        var = getVar();
        // Null Pointer Exception.
        System.out.println("var string length is " + var.length());
    }

    public String getVar() {
        return "String from A";
    }
}

Or

Making getVar method final

static class A {
    private final String var;

    public A() {
        var = getVar();
        // Null Pointer Exception.
        System.out.println("var string length is " + var.length());
    }

    public final String getVar() {
        return "String from A";
    }
}

The author trying to suggest ways to prevent the above problem. However, the solution seems cumbersome as there are some rules to be followed.

http://benpryor.com/blog/2008/01/02/dont-call-subclass-methods-from-a-superclass-constructor/

Beside making final and the author suggested way, is there more ways to prevent the above problem (Don’t call subclass methods from a superclass constructor) from happen?

Upvotes: 3

Views: 1251

Answers (1)

OscarRyz
OscarRyz

Reputation: 199215

Making getVar method final

This is definitely what you need to do.

If you're relying on the functionality of a method to initialize an object, you shouldn't let subclasses break that method.

Answering your question, another way to prevent it is to make getVar private in A.

See this simplified version of your code:

// A.java
class A {
    private final String var;
    public A(){
        var = getVar();
        var.length();
    }
    private String getVar(){
        return "This is the value";
    }
}

class B extends A {
    private final String other;
    public B(){
        other = "Other string";
    }
    public String getVar(){
        return other;
    }
}

class Main{
    public static void main( String [] args ) {
        new B();
    }
}

BTW, why did you put those as static nested classes, just to create confusion?

Upvotes: 3

Related Questions