Base Class:
public class Base {
private String baseMessage = "Hello!";
public Base() {
printMessage();
}
public void printMessage() {
System.out.println(baseMessage.toString());
}
}
Derived Class:
public class Derived extends Base {
private String derivedMessage = "World!";
public Derived () {
super();
}
#Override
public void printMessage() {
super.printMessage();
System.out.println(derivedMessage.toString());
}
public static void main(String[] args) {
// new Base();
new Derived();
}
}
When I run
new Base();
I get the expected output:
Hello!
When I Run
new Derived();
I get
Hello!
Hello!
then NullPointerException. This seems a bit weird to me. I don't know why it's printing it out then throwing a nullpointerexception, rather straight up throwing it. Maybe it's Eclipse, I don't know.
What's the underlying concept here?
Before you read this, read
What's wrong with overridable method calls in constructors?
The body of a child class constructor is compiled to something like this
public Derived () {
super();
initializeInstanceFields();
// all instance fields are initialized either to their default value
// or with their initialization expression
}
In other words, by the time the Derived#printMessage() is called because of polymorphism from the super constructor, the Derived.derivedMessage is still null.
Here's the step by step:
new Derived();
invokes the Derived constructor
public Derived () {
super();
}
which invokes the super constructor
public Base() {
printMessage();
}
Here, before the printMessage(), this class' instance fields are initialized, so baseMessage gets the value of "Hello!". When printMessage() gets invoked, because this is a Derived object and Derived overrides the methods, its implementation is invoked.
#Override
public void printMessage() {
super.printMessage();
System.out.println(derivedMessage.toString());
}
This calls the super implementation
public void printMessage() {
System.out.println(baseMessage.toString());
}
which prints
Hellow!
The method returns back to Derived#printMessage and attempts to invoke toString() on derivedMessaged, but, as I've explained earlier, the derivedMessage hasn't been initialized yet, so it is null. Dereferencing null causes NullPointerException.
And this is why you don't invoke overridable methods from constructors.
Related
I'm learning about inheritance and am working with this simple program that has has a superclass and a subclass as shown below. My question isn't specific to this program; however, this is where I've first seen this happen so I'm using it as an example for a more general conceptual question. Why does simply instantiating the class run the constructors and output the contents? My previous understanding was that instantiating the class simply creates the object but it wont do anything.
SuperClass1.java
public class SuperClass1 {
public SuperClass1(){
System.out.println("This is the superclass constructor.");
}
}
SubClass2.java
public class SubClass2 extends SuperClass1
{
public SubClass2()
{
System.out.println("This is the subclass constructor.");
}
}
Main.java
public class Main {
public static void main(String[] args)
{
SubClass2 obj1 = new SubClass2(); // why should this print something?
}
}
Output
This is the superclass constructor.
This is the subclass constructor.
First of all, instantiating an object means calling (and executing) the constructor, that is what it is for.
So, this:
SubClass2 newInstance = <createNewInstance>;
newInstance.<init()>;
is both done by the constructor call new SubClass2() in Java. There is no separation between "constructing" the object and "initialising" its properties.
Furthermore, if you do not explicitly call another constructor of a super class the default constructor (the one without arguments) is automatically called first thing when creating an object of a class. So instantiating an object of the subclass calls the superclass contructor (which prints the first line), and then prints the second line itself.
More in detail, the subclass looks like this behind the scene:
public class SubClass2 extends SuperClass1
{
public SubClass2()
{
super(); // calls the superclass constructor
System.out.println("This is the subclass constructor.");
}
}
Because the constructor you call includes a print statement.
You call the constructor method SubClass2() which has a print statement in it.
The statements are not printed because the class ist loaded, but because an object of that class in instantiated and the constructors are called:
That a class can be loaded without using constructor is demonstrated by the following code:
public class Test {
public static void main(String[] args) {
try {
Class.forName("Test$Inner");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
static class Inner {
static {
System.out.println("static initializer");
}
public Inner() {
System.out.println("inner ctor");
}
}
}
running that program shows that only the static class initializer is called and no constructor.
I have a NullPointerException when I try to do something like that :
class A {
public A() {
aMethod();
}
public void aMethod() {
//Some stuff
}
}
class B extends A {
List<String> list = new ArrayList<String>
public B() {
super();
}
#Override
public void aMethod() {
super.aMethod();
list.add("Something"); //NullPointerException
}
}
I can't instantiate the list before call super in the constructor, and I think it's not proper to instantiate it into the "aMethod".
This illustrates the dangers of calling a subclass method through polymorphism from a superclass constructor.
Your B constructor calls A's constructor explicitly, which calls aMethod. But at this point, nothing in B is initialized yet, so list is still null. That causes the NullPointerException. Java won't initialize instance variables until after the call to the superclass constructor has completed.
The best way to solve this is to move the initialization of the list into the constructor:
Method:
super();
list.add("Something"); // No more NullPointerException
It's also best not to call methods that can be overridden in constructors, because in the superlcass constructor, the subclass portion of the object hasn't been initialized yet.
What is the difference between these two calls? How should this be done properly?
//package test;
public class SomeClass {
public SomeClass() {
doSomething();//Warning - Overridable method call in constructor
SomeClass.this.doSomething();//Seems OK
}
public void doSomething() {
//...
}
}
I want to use doSomething() just for convenience in the same class. I have no intentions to override it later. One idea is to declare it final. But still it is not clear if SomeClass.this.doSomething(); is safe to use in this situation.
The compiler warning notification somewhat says what can happen. If a subclass overrides the doSomething method, it can change the behavior when creating the class instance, which may be dangerous or not, depending on your design. Note that it's a warning, not a compiler exception.
To prove this, just extended your code to test it:
class SomeClass {
public SomeClass() {
doSomething();//Warning - Overridable method call in constructor
SomeClass.this.doSomething();//Seems OK, but is not
}
public void doSomething() {
System.out.println("parent");
}
}
public class SomeOtherClass extends SomeClass {
#Override
public void doSomething() {
System.out.println("child");
}
public static void main(String[] args) {
SomeClass a = new SomeClass();
SomeOtherClass b = new SomeOtherClass();
}
}
Prints:
parent
parent
child
child
If you just want that no other class can override doSomething method, mark it as final:
class SomeClass {
public SomeClass() {
doSomething();//Warning - Overridable method call in constructor
SomeClass.this.doSomething();//Seems OK
}
public final void doSomething() {
System.out.println("parent");
}
}
Then if any subclass tries to override it, the compiler will throw an error:
public class SomeOtherClass extends SomeClass {
#Override
public void doSomething() { //compiler error
System.out.println("child");
}
//...
}
Since the subclass is not constructed yet, is it unsafe to call an abstract method in a super class constructor?
However, if the method's behaviour does not depend on the constrction of subclass, e.g. just return a constant with regard to the subclass, is it still unsafe or will it work reliably?
Moreover, if it works, how to do it if I do not want to make the super class abstract?
Update: for last question
public class SuperClass {
public SuperClass() {
System.out.println(getValue());
}
public String getValue() {
return "superclass";
}
public static void main(String[] args) {
new SubClass();
}
}
class SubClass extends SuperClass {
public SubClass() {
super(); // Comment out this or not will not affect the result
}
public String getValue() {
return "subclass";
}
}
I wrote a test, and figure it out: the result is : subclass
Thanks to #Tim Pote's example.
It is generally (though not necessarily) considered unsafe. As you said, the superclass may not be fully constructed, and therefore won't be ready to handle all of the calls a subclass might make in its overridden method.
However, in the case that all subclasses simply return a constant that isn't dependent on any other method, then it should be fine. The only downside is that you can't guarantee that a subclass will override that method in an appropriate manner.
In regards to your last question: this isn't an issue of an abstract vs. concrete superclass. This is an issue with calling overridable methods in a constructor. Abstract vs. concrete is beside the point.
Edit in response to the OP's comment
I'm not certain what you mean by "polymorphiscly". Calling a virtual method always invokes the sub-most implementation. The only time a superclasses implementation is invoked is via the super keyword. For example:
public class SuperClass {
public SuperClass() {
System.out.println(getValue());
}
public String getValue() {
return "superclass";
}
public static void main(String[] args) {
new SubClass();
}
public static class SubClass extends SuperClass {
public String getValue() {
return "subclass";
}
}
}
prints subclass.
And this:
public class SuperClass {
public SuperClass() {
System.out.println(getValue());
}
public String getValue() {
return "superclass";
}
public static void main(String[] args) {
new SubClass();
}
public static class SubClass extends SuperClass {
public String getValue() {
return super.getValue() + " subclass";
}
}
}
prints superclass subclass
As others have explained there is an inherent risk in calling abstract methods in super class constructor.
The one exception I have found is when the subclass provides some "constant" information, e.g getId(), getHandledMessages() and suchlike.
I have the following situation:
public abstract class A {
private Object superMember;
public A() {
superMember = initializeSuperMember();
// some additional checks and stuff based on the initialization of superMember (***)
}
protected abstract Object initializeSuperMember();
}
class B extends A {
private Object subMember;
public B(Object subMember) {
super();
subMember = subMember;
}
protected Object initializeSuperMember() {
// doesn't matter what method is called on subMember, just that there is an access on it
return subMember.get(); // => NPE
}
}
The problem is that I get a NPE on a new object B creation.
I know I can avoid this by calling an initializeSuperMember() after I assign the subMember content in the subclass constructor but it would mean I have to do this for each of the subclasses(marked * in the code).
And since I have to call super() as the first thing in the subclass constructor I can't initialize subMember before the call to super().
Anyone care to tell me if there's a better way to do this or if I am trying to do something alltogether wrong?
Two problems:
First, you should never call an overrideable member function from a constructor, for just the reason you discovered. See this thread for a nice discussion of the issue, including alternative approaches.
Second, in the constructor for B, you need:
this.subMember = subMember;
The constructor parameter name masks the field name, so you need this. to refer to the field.
Follow the chain of invocation:
You invoke the B() constructor.
It invokes the A() constructor.
The A() constructor invokes the overridden abstract methot
The method B#initializeSuperMember() references subMember, which has not yet been initialized. NPE.
It is never valid to do what you have done.
Also, it is not clear what you are trying to accomplish. You should ask a separate question explaining what your goal is.
Hum, this code does not look good and in all likelyhood this is a sign of a bad situation. But there are some tricks that can help you do what you want, using a factory method like this:
public static abstract class A {
public abstract Object createObject();
}
public static abstract class B extends A {
private Object member;
public B(Object member) {
super();
this.member = member;
}
}
public static B createB(final Object member) {
return new B(member) {
#Override
public Object createObject() {
return member.getClass();
}
};
}
The problem is when you call super(), the subMember is not initialized yet. You need to pass subMemeber as a parameter.
public abstract class A {
public A (Object subMember) {
// initialize here
}
}
class B extends A {
public B (Object subMember) {
super(subMember);
// do your other things
}
}
Since you don't want to have subMember in the abstract class, another approach is to override the getter.
public abstract class A {
public abstract Object getSuperMember();
protected void checkSuperMember() {
// check if the supberMember is fine
}
}
public class B extends A {
private Object subMember;
public B(Object subMember) {
super();
this.subMember = subMember;
checkSuperMemeber();
}
#Override
public Object getSuperMember() {
return subMember.get();
}
}
I hope this can remove your duplicate code as well.