Constructor Chaining

When you define a class, Java guarantees that the class's constructor method is called whenever an instance of 
that class is created. It also guarantees that the constructor is called when an instance of any subclass is 
created. In order to guarantee this second point, Java must ensure that every constructor method calls its 
superclass constructor method. If the first statement in a constructor is not an explicit call to a 
constructor of the superclass with the super keyword, then Java implicitly inserts the call super() -- that 
is, it calls the superclass constructor with no arguments. If the superclass does not have a constructor that 
takes no arguments, this causes a compilation error.

There is one exception to the rule that Java invokes super() implicitly if you do not do so explicitly. If the 
first line of a constructor, C1, uses the this() syntax to invoke another constructor, C2, of the class, Java 
relies on C2 to invoke the superclass constructor, and does not insert a call to super() into C1. Of course, 
if C2 itself uses this() to invoke a third constructor, C2 does not call super() either, but somewhere along 
the chain, a constructor either explicitly or implicitly invokes the superclass constructor, which is what is 
required.

Consider what happens when we create a new instance of the GraphicCircle class. First, the GraphicCircle 
constructor shown in our previous example is invoked. This constructor explicitly invokes a Circle constructor 
and that Circle constructor implicitly calls super() to invoke the constructor of its superclass, Object. The 
body of the Object constructor runs first, followed by the body of the Circle constructor, and finally 
followed by the body of the GraphicCircle constructor.

What this all means is that constructor calls are "chained" -- any time an object is created, a sequence of 
constructor methods are invoked, from subclass to superclass on up to Object at the root of the class 
hierarchy. Because a superclass constructor is always invoked as the first statement of its subclass 
constructor, the body of the Object constructor always runs first, followed by the body of its subclass, and 
on down the class hierarchy to the class that is being instantiated.

The Default Constructor

There is one missing piece in the description of constructor chaining above. If a constructor does not invoke 
a superclass constructor, Java does so implicitly. But what if a class is declared without any constructor at 
all? In this case, Java implicitly adds a constructor to the class. This default constructor does nothing but 
invoke the superclass constructor. For example, if we did not declare a constructor for the GraphicCircle 
class, Java would have implicitly inserted this constructor:

public GraphicCircle() { super(); }

Note that if the superclass, Circle did not declare a no-argument constructor, then this automatically 
inserted default constructor would cause a compilation error. If a class does not define a no-argument 
constructor, then all of its subclasses must define constructors that explicitly invoke the superclass 
constructor with the necessary arguments. It can be confusing when Java implicitly calls a constructor or 
inserts a constructor definition into a class -- something is happening that does not appear in your code! 
Therefore, it is good coding style, whenever you rely on an implicit superclass constructor call or on a 
default constructor, to insert a comment noting this fact. Your comments might look like those in the 
following example:

class A {
  int i; 
  public A() {
    // Implicit call to super() here 
    i = 3; 
  }
}

class B extends A {
  // Default constructor: public B() { super(); }
}

If a class does not declare any constructor, it is given a public constructor by default. Classes that do not 
want to be publically instantiated, should declare a protected constructor to prevent the insertion of this 
public constructor. Classes that never want to be instantiated at all (in one particular, specific way,) 
should define that particular constructor private.

--

All questions should be discussed in lab. Here they are now:

You attempt to compile and run this code:

class Alpha {
  public static void main(String[] args) {
    Beta f = new Beta();
  }
  Alpha(int i) {  }
}
class Beta extends Alpha { }

What is the outcome?

Possible answers:

(a) The code does not compile because Beta does not define a no-args constructor. 
(b) The code does not compile because Beta does not define any constructors whatsoever. 
(c) The code compiles and runs succesfully, with no output. 
(d) The code does not compile because Alpha doesn't define a no-args constructor. 
(e) None of the above.

You attempt to compile and run this code:

class Alpha {
  public static void main(String[] args) {
    Beta f = new Beta(3);
  }
  Alpha (int i) {  }
}
class Beta extends Alpha {
  Beta(int i) {
  }
}

What is the outcome?

You attempt to compile and run this code:

class Alpha {
  public static void main(String[] args) {
    Beta f = new Beta(3);
  }
  Alpha() { System.out.println(0); }
  Alpha(int i) {
    System.out.println(i);
  }
}
class Beta extends Alpha {
  Beta()      { }
  Beta(int i) { }
}

What is the outcome?

You attempt to compile and run this code:

class Alpha {
  public static void main(String[] args) {
    Beta f = new Beta(3);
  }
  Alpha() {
    System.out.println(0);
  }
  Alpha(int i) {
    System.out.println(i);
  }
}
class Beta extends Alpha {
  Beta() {
    super(6);
  }
  Beta(int i) {
    this();
  }
}

What is the outcome?

You attempt to compile and run this code:

class Alpha {
  public static void main(String[] args) {
    Beta f = new Beta(3);
  }
  Alpha() {
    System.out.println(0);
  }
  Alpha(int i) {
    System.out.println(i);
  }
}
class Beta extends Alpha {
  Beta() {
    super(6);
  }
  Beta(int i) {
    super(3);
    this();
  }
}

What is the outcome?

You attempt to compile and run this code:

class Alpha {
  public static void main(String[] args) {
    Beta f = new Beta(12);
  }
  Alpha() {
    System.out.print(0);
  }
  Alpha(int i) {
    System.out.print(i);
  }
}
class Beta extends Alpha {
  Beta() {
  }
  Beta(int i) {
    this();
    System.out.print(3);
  }
}

What is the outcome?

You attempt to compile and run this code:

class Alpha {
  public static void main(String[] args) {
    Alpha f = new Beta();
    System.out.println(f.test(3));
  }
  String test(int i) {
    return (i + 2) + " ";
  }
}
class Beta extends Alpha {
  String test(int i) {
    return (i + 1) + " ";
  }
  String test(long i) {
    return i + " ";
  }
}

What is the outcome?

You attempt to compile and run this code:

class Alpha {
  public static void main(String[] args) {
    Beta f = new Alpha();
    System.out.println(f.test(3));
  }
  String test(int i) {
    return (i + 2) + " ";
  }
}
class Beta extends Alpha {
  String test(int i) {
    return (i + 1) + " ";
  }
}

What is the outcome?

You attempt to compile and run this code:

class Alpha {
  public static void main(String[] args) {
    Alpha f = new Alpha();
    System.out.println(f.test(3));
  }
  String test(int i) {
    return (i + 2) + " ";
  }
}
class Beta extends Alpha {
  String test(int i) {
    return (i + 1) + " ";
  }
}

What is the outcome?

You attempt to compile and run this code:

class Alpha {
  public static void main(String[] args) {
    Beta f = new Beta();
    System.out.println(test(3));
  }
  String test(int i) {
    return (i + 2) + " ";
  }
}
class Beta extends Alpha {
  String test(int i) {
    return (i + 1) + " ";
  }
}

What is the outcome?

You attempt to compile and run this code:

abstract class Alpha {
  int value;
  Alpha (int value) {
    this.value = value;
    System.out.println(value);
  }
  public static void main(String[] args) {
    Beta f = new Beta(2011);
  }
}
class Beta extends Alpha {
  Beta  (int value) { super(value); }
}

What is the outcome?

You attempt to compile and run this code:

class Alpha {
  public static void main(String[] args) {
    System.out.println("... won't compile");
  }
  public static void main() {
    System.out.println("... will not run");
  }
}

What is the outcome?

You attempt to compile and run this code:

abstract class Alpha {
  abstract void complain();
}
class Beta extends Alpha {
  void complain(String s) {
    System.out.println(s);
  }
}
class Tester {
  public static void main(String[] args) {
    Beta f = new Beta();
    f.complain("There's a tomato in every automaton.");
  }
}

What is the outcome?

You attempt to compile and run this code:

class Alpha {
  String message;
  Alpha (String msg) { message = msg; }
}
class Beta extends Alpha {
  Beta (String msg)  { message = msg; }
}
class Tester {
  public static void main(String[] args) {
    Beta f = new Beta("Greetings");
    System.out.println(f.message);
  }
}

What is the outcome?

You attempt to compile and run this code:

class Vegetable { } 
class Cabbage extends Vegetable { }
class Kohlrabi extends Cabbage { } 
class Kroger {
  public static void main(String[] args) {
    Cabbage a = new Kohlrabi(); 
  }
}

What is the outcome?

You attempt to compile and run this code:

class Vegetable { } 
class Cabbage extends Vegetable { }
class Kohlrabi extends Cabbage { } 
class Kroger {
  public static void main(String[] args) {
    Kohlrabi a = new Vegetable(); 
  }
}
What is the outcome?

--


import java.awt.event.*; 

public class Mason implements ActionListener {
  public void actionPerformed(ActionEvent e) {
    System.out.println("Ouch!");  
  }
}


import javax.swing.Timer; 

public class Example {
  public static void main(String[] args) {
    
    Timer t = new Timer(100, new Mason()); 
    
    t.start(); 
    
  }
}

--