xheyhenry
xheyhenry

Reputation: 1069

Abstract class: output of this code

Currently doing a practice test on abstract classes and interfaces and ran into this problem:

  public class Test {
  public static void main(String[] args) {
    new Circle9();
  }
}

public abstract class GeometricObject {
  protected GeometricObject() {
    System.out.print("A");
  }

  protected GeometricObject(String color, boolean filled) {
    System.out.print("B");
  }
}

public class Circle9 extends GeometricObject {
  /** Default constructor */
  public Circle9() {
    this(1.0);
    System.out.print("C");
  }

  /** Construct circle with a specified radius */
  public Circle9(double radius) {
    this(radius, "white", false);
    System.out.print("D");
  }

  /** Construct a circle with specified radius, filled, and color */
  public Circle9(double radius, String color, boolean filled) {
    super(color, filled);
    System.out.print("E");
  }

}

Why is the output BEDC? I thought new Circle9() would first invoke the no-arg constructor of the Circle 9 class, printing A, and then the other letters, but I'm having a hard time understanding the path of the code.

Upvotes: 2

Views: 953

Answers (6)

Paul Samsotha
Paul Samsotha

Reputation: 209004

this question doesnt really have anything to do with abstract classes or interfaces. It's more about inheritance.

Your answer is this. When you call a subclass, it's superclasses are first called, WITH their no-arg consructor, UNLESS you explicitly call a different constructor, which you have. when you call:

Circle9()

which

this(1.0)

calls

Circle(doubleradius)

which

this(radius, "white", false)

calls

Circle(double, string, boolean)

which

super(Color, filled)

calls

GeometricObject(string, boolean)

which is the last in the inheritance chain, so its actions are performed first

print("B")

then the program runs backward through the chain and prints the rest according to position in the chain, the same way it moved forward, is the same way it will go backward, hence

print("E")
print("D")
print("C")

Upvotes: 1

Bohemian
Bohemian

Reputation: 425043

Follow the call stack:

  • new Circle9() invokes Circle9()
  • Circle9() calls this(1.0)
  • Circle9(double) calls this(radius, "white", false)
  • Circle9(double, String, boolean) calls super(color, filled)
  • GeometricObject(String, boolean) prints B
  • Circle9(double, String, boolean) prints E
  • Circle9(double) prints D
  • Circle9() prints C

Upvotes: 5

millimoose
millimoose

Reputation: 39950

Constructors are somewhat special - with the exception of Object(), each constructor in any class must call one, and only one other constructor, either in the current class or its superclass, before any other code in it runs. You can choose which constructor this is either explicitly, by using this(...) or super(...). If you do not do this, only then will the no-args constructor of the superclass be implicitly called. (As if you used super().)

Which means you can consider this as a dependency chain that starts with the constructor you're invoking with new, and ultimately has to reach Object(). In your example, this chain would be:

Circle9() => prints "C"
  |
  | (explicit)
  v
Circle9(double) => prints "D"
  |
  | (explicit)
  v
Circle9(double,String,boolean) => prints "E"
  |
  | (explicit)
  v
GeometricObject(String, boolean) => prints "B"
  |
  | (implicit)
  v
Object() => does nothing

You then run the actual code in the constructors, walking this chain backwards.

The reason why "A" is never printed is that GeometricObject() never gets called because neither constructor of Circle9 nor GeometricObject(String,boolean) calls ("depends on") it - they all explicitly call some other constructor.

Upvotes: 5

Tim
Tim

Reputation: 2027

The no-arg constructor of the Circle9 class prints C, not A.

Your order of calls is: new Circle9(); new Circle9(double); new Circle9(double, String, boolean); new GeometricObject(String, boolean); System.out.print("B"); System.out.print("E"); System.out.print("D"); System.out.print("C");

GeometricObject() is never called; if GeometricObject(String, boolean) explicitly called this() as its first line, you'd see A, but it's not called by default from another constructor. (A constructor must be called to make the object, but nothing requires that the no-args constructor be called from a constructor that has arguments, nor vice versa.)

Upvotes: 4

Sinkingpoint
Sinkingpoint

Reputation: 7624

In this case, the empty constructor of the Circle9 class calls the double constructor of the Circle9 class which calls the radius, String, boolean constructor of the Circle9 class which calls the String, boolean super constructor of the GeometricObject class. This then works backwards as functions return - B (Geometric Object), E - Third Circle 9, D - Second Circle9, C - First Circle9.

Upvotes: 1

Thomas W
Thomas W

Reputation: 14164

Calling new Circle9() does not invoke the no-arg superclass constructor, it goes off elsewhere. Read your own code.

public Circle9() {
    this(1.0);  // calls to Circle(double radius) constructor, & on from there..
    System.out.print("C");
}

Upvotes: 0

Related Questions