3

I think we already discussed this issue in this post here Inheritance in Java simple clarification

But since the example here is a bit simpler and the point i want to be clarified is different i´ll give it a shot.

First, the two classes to discuss:

public class SuperClass{
    SuperClass() {
        foo();
    }

    public void foo() {
        System.out.println("Super.foo()");
    }

    public static void main(String[] args) {
            SuperClass tn = new DerivedClass();
            tn.foo();
    }
}

public class DerivedClass extends SuperClass{
    String i;

    TrickyB() {
        i = "aksjhdf";
    }

    public void foo() {
        System.out.println("In derived.foo() --> " + i);
    }
}

I (at least I think) understand the concepts of polymorphism and i know why DerivedClass.foo() is called when invoking

new DerivedClass();

I see an inconsistency here:

At the time we invoke the c´tor of DerivedClass the c´tor of the SuperClass is called implicitly (so to say as the first line of the Derived c´tor).

So in the Super c´tor, DerivedClass is not fully initialised, which makes working with this class useless. This point is reflected in the output of this program

In derived.foo() --> null
In derived.foo() --> aksjhdf

The first line reflects my confusion:

Why is DerivedClass.foo() called? The object is not ready yet, so doing anything with it is nonsense in my eyes.

Can anyone explain the reasons to me. I think this absolutely counter intuitive.

BTW: I would have expected SuperClass.foo() to be called, since, as I said, it doesnt make any sense to work with an "unready" object.

On the other Hand: As I think of it. It doesn´t make any sense to me neither, that, while I´m in the c´tor of SuperClass, DerivedClass.foo() is called!

How would I call SuperClass.foo() in my case?

Community
  • 1
  • 1
Tomas Longo
  • 95
  • 1
  • 7

5 Answers5

7

Why is DerivedClass.foo() called? The object is not ready yet, so doing anything with it is nonsense in my eyes.

No. The object has already been created. Constructors don't create objects, it just initializes them. The object is created by new operator here.

I would have expected SuperClass.foo() to be called

As already explained, it's not that object is not created. It's already been. And that invocation will call the overridden method. That is why you should never call overridden method from constructor. You'll see unexpected behaviour.

SuperClass does not know anything about any derived classes.

Well, it doesn't need to know. The fact that the method invocation invokes the derived class method has nothing to do with whether superclass knows about subclass or not. The actual method that will be invoked is decided at runtime, based on the actual object in picture. Since here, the object is of type DerivedClass, the method in the DerivedClass if present will be invoked.

How would I call SuperClass.foo() in my case?

You don't. That's the whole point. Go through the post that I linked for step-by-step explanation.

Community
  • 1
  • 1
Rohit Jain
  • 209,639
  • 45
  • 409
  • 525
  • Thanks for the step-by-step explanation. I know that DerivedClass is already present (yet not initialised) what bothers me is the possibility to access it while it is not useable. – Tomas Longo Feb 17 '14 at 18:45
  • @TomasLongo That is the issue. Java doesn't stop you from doing these stuffs. Probably because spotting these kinds of stuffs, and marking it as some error would not be feasible for the compiler. There are some things that you've to handle. – Rohit Jain Feb 17 '14 at 18:49
3

Unlike C++, Java sets the runtime type of the object at the time of allocation, before any constructor is run. This is why polymorphic behavior occurs during initialization.

This behavior can be useful sometimes, under controlled circumstances. In most cases, however, it's a good idea to avoid it, because you are leaking an uninitialized object to code that is external to your class (via the this reference in the virtual method). You should try only calling private (or final) methods from the constructor, whenever possible.

Theodoros Chatzigiannakis
  • 28,773
  • 8
  • 68
  • 104
0

Why is DerivedClass.foo() called?

Because this is Java language design. It's on the developer to ensure invariant classes inside of a inheritance hierarchy by himself, not by the language.

How would I call SuperClass.foo() in my case?

From the derived class: super.foo();

Smutje
  • 17,733
  • 4
  • 24
  • 41
0

DerivedClass.foo() is called within DerivedClass. The foo() is called for the object itself. This, by inheritance, can also be equal to SuperClass.foo(). But, because of polymorphism also can be different. If you explicitely want the foo() from SuperClass, then call super.foo(). By the way, because DerivedClass.foo() is dependant of i, you should initialize i first.

scheurneus
  • 155
  • 5
0

As Rohit said, an overridden method (or more precisely, a method that could be overridden) shouldn't be called from a constructor. Here's a way around that:

public class SuperClass{
    SuperClass() {
        privateFoo();
    }

    public void foo() {
        privateFoo();
    }

    private void privateFoo() {   // cannot be overridden since it's private
        System.out.println("Super.foo()");
    }

}

Make the foo method just a one-line method that calls a private version. Of course, if it has arguments and/or a return value, you'd include those.

ajb
  • 31,309
  • 3
  • 58
  • 84