Thank you, Roel! I really appreciate what you are doing; every time I see any of your posts I just know that it will be up to the point and fun to read. Honestly
Now, to the pet lion puzzle.
You were right: I didn't get it; at least, not quite. Failed twice to solve the problem. It took me at least ten minutes to see the light. Here's what I was thinking:
Line 16 creates an anonymous Lion object, calls on it its own
doNameStuff() method with "Jack" as the method's parameter.
Line 8 changes the arg
name to lower case and assigns the resulting
String (i.e., "jack") to the current object's field named
name (i.e.,
this.name); this var's value will be printed on line 12.
Line 9 creates an anonymous Animal object and sets its
name to "ANIMAL". The current object is unaffected by this change because these two objects are separate.
Line 10 creates another object referenced to as
a and whose runtime type is actually Lion. Since the object is completely new - fresh from the owen, so to speak, - its fields are pristine and, therefore, its
name is simply "Lion"…
I do this mistake quite often: treating fields as if they were virtual methods; as soon as I see a superclass type to the left of
new and a subclass on the right, a switch gets thrown in my head reminding me that "the ref type says which methods and fields are available in principle, and the actual type dictates the concrete implementation at runtime." What I tend to forget is that this rule talks about *implementation*, about overriding - and vars aren't overridden, they are shadowed. So from now on I'm going to use another mnemonic: "When it comes to overridden methods, actual type rules; when it comes to shadowed vars, ref type is the king". Hopefully, I got it now...
Alright, trying to do the trick right this time:
The object
a's
name is "Animal" precisely because its reference type *is* Animal. Were it Lion (as if created by
Lion a = new Lion(); ), its
name would have been Lion.
Fair enough. Taking next step.
The var
name (which is going to be used in another slot in the
printf stat) gets assigned "ANIMAL" on line 11.
As for the
new Lion().name slot, it should be easy by now: its value is "Lion" because the object itself is a Lion (unlike the Animal-type object created on line 10).
Finally,
super.name is "Animal" because this variable is shadowed by declaring a new var with the same name on line 5, and by prefixing
super we access this var directly in the superclass. Should we opt for a simple re-assignment instead of shadowing,
super.name would have become "Lion" because the change in the value would've affected the superclass, too.
Placing all together, the code should print 'ANIMAL jack Lion Animal'.
Incidently, making
name on line 2 non-static does not affect the outcome… but doing it on line 5 does! (sighs) Another brainer to crack… I love
Java (sighs again)…
I have to run now - sorry! - but will be back soon to answer your question: how and what did I do to prepare myself for the exam.
Meanwhile, many thanks again for helping me - and many others - to get a solid footing in the Java world!