Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java: How constructors and methods behave with inheritance

Java seems to be inconsistent in how class constructors and methods deal with inheritance.

Case 1 - Methods:

public class HelloWorld
{
  public static void main(String[] args)
  {
    Bee b = new Bee();
    b.foo();
  }
}

class Insect {
  public void foo() {
    this.bar();
    System.out.println("Insect foo");
  }

  public void bar() {
    System.out.println("Insect bar");
  }
}

class Bee extends Insect {
  @Override
  public void foo() {
    super.foo();
    System.out.println("Bee foo");
  }

  @Override
  public void bar() {
    System.out.println("Bee bar");
  }
}

The above code outputs the following:

Bee bar

Insect foo

Bee foo

Notice the call to "this.bar()" in Insect's foo() method actually goes back and calls Bee's bar() method (instead of calling Insect's bar() method).

Case 2 - Constructors:

public class HelloWorld
{
  public static void main(String[] args)
  {
    Bee i = new Bee(1);
  }
}

class Insect {
  public Insect(int size) {
    this(size, 123);
    System.out.println("Constructor: Insect size");
  }

  public Insect(int size, int height) {
    System.out.println("Constructor: Insect size, height");
  }
}

class Bee extends Insect {
  public Bee(int size) {
    super(size);
    System.out.println("Constructor: Bee size");
  }

  public Bee(int size, int height) {
    super(size, height);
    System.out.println("Constructor: Bee size, height");
  }
}

The above outputs the following.

Constructor: Insect size, height

Constructor: Insect size

Constructor: Bee size

Notice the call to "this(size, 123);" in Insect's constructor goes to Insect's 2nd constructor instead of bee's 2nd constructor.

So in summary, method calls go back to the subclass while constructor calls stay in the superclass. Can anyone explain why?

like image 640
Nightfire Avatar asked Oct 29 '22 07:10

Nightfire


1 Answers

Beyond the correct information in the comments about methods being not the same as constructors - you are actually over-simplifying things.

You see, when you write constructors, you have to decide if you intend to use a "same class" constructor (when you use this()) - or if you want to invoke a super class constructor (using super()) instead. There is no middle ground here - you have to be explicit about this!

Keep in mind: the responsibility of a constructor is to initialize an object of the corresponding class. It can make a huge difference if you call this(whatever) or super(whatever) within your constructors.

The compiler can't know what you intend to do. Therefore you have to be explicit about the exact other constructor you want to be invoked.

And beyond that - it simply doesn't make sense to have polymorphism kick in here like this. You absolutely want that object initialization takes place as you expect it to happen. Because wrongly initialized objects for sure create problems later on.

Your idea of making constructors polymorphic basically means that you determine at runtime which constructor to invoke. But you already know that you are in class X, and that you have to initialize a new X object. There is nothing to gain from allowing polymorphism here. To the contrary - doing so would allow for very strange and bizarre problems that would be purely runtime only!

like image 55
GhostCat Avatar answered Nov 15 '22 05:11

GhostCat