Here is a rundown of the behavior of each line of code in the Superclass-Subclass review example. While I am not renaming these classes here, it may be easier to think of this as a Mammal-Human relationship as that is a real world example that is (hopefully) easier cognitively.
BIG IDEA: The right-hand side of the assignment operator dictates what will be put into memory. The left-hand side determines how the object should be viewed, so only methods that are in the left-hand side cast are eligible to be executed. If such a method is called and appears in that cast class (or interface), then go back to what is in memory and try to execute it at that level, delegating it up through the superclass chain until the method is found.
BIG IDEA: If no superclass constructor is explicitly called, the zero-input superclass constructor will automatically be called before any other code is executed in the subclass constructor. If there is no zero-input superclass constructor, there will be a compiler error. The superclass will call its own superclass constructor and so on until Object is reached.
BIG IDEA: Ultimately, every class has Object at the top of its hierarchy.
Line 1:
Superclass sup1 = new Superclass();
Output:
1 a b 0
A Superclass is being put into memory and sup1 is being cast as a Superclass. Everything is being done on the Superclass level. The zero-input constructor calls the two-paramter constructor, so "0 " must be printed after everything else is done. The two-paramter constructor prints "1 ", then calls a(), which prints "a ", then calls b(), which prints "b ".
Line 2:
Subclass sub2 = new Subclass();
Output:
1 c a d 0 2
A Subclass is being put into memory and cast as a Subclass. Since it extends Superclass, this gets kind of messy.
BIG IDEA: When a constructor calls another constructor with the keyword this, the call remains at the same level (i.e., in the same class) as the constructor. When a method is called with the keyword this, it is executed at the level of the object type placed in memory.
In this example, the zero-input constructor for Subclass is called. It calls the Superclass's zero-input constructor, so all the stuff that involves must be done before printing the "2 ".
In Superclass's zero-input constructor, the two-paramter Superclass constructor is called (remember, this when calling a constructor stays at the same class level). That call must complete before "0 " is printed, so the "0 " is next-to-last before the "2 ".
In Superclass's two-parameter constructor, the "1 " is printed immediately. After a couple of field variable assignments, a() is called. Since a() is a method in the Superclass, it can be called. Since the object being created in memory is of type Subclass, a() is called in Subclass, not Superclass.
Subclass's a() method prints "c " and then specifically calls the Superclass's a() method.
Superclass's a() method prints "a " and calls b(). The keyword this is being used to call a method, not a constructor, so first a check is made to verify that there exists a method b() in Superclass (there is) and then b() is called by the object being placed in memory, which is type Subclass. So, it is Subclass's b() method that gets called.
Subclass's b() method prints "d ". After that, the code returns to the constructors and the "0 " and "2 " finally get printed, as described above.
Line 3:
Subclass thing = new Superclass(1, "Wilma");
Output: None, as this won't compile.
A Superclass is being put into memory and an attempt is being made to cast it as a Subclass. This is like putting a Mammal into memory and trying to cast it as a Human. Not all Mammals are Humans, so that cast cannot be assumed to work by the compiler, producing an error.
Line 4:
Superclass thing2 = new Subclass(2, "Dino");
Output:
1 c a d 3
This is similar to Line 2. The "3 " prints last because it gets executed after the Superclass constructor call stuff. "0 " and " 2" are not printed because neither the Subclass nor the Superclass zero-input constructors are ever called. Everything else is the same as for Line 2.