I feel kind of silly asking this, but I can't seem to wrap my head around polymorphism. The overarching concept is clear to me, however, it is with its implementations that I am struggling.
The following question (from Jeanne's and Scott's OCA book) tricks me every time, which is why it is a great question. I know a similar topic exists on the forum, but my question is slightly different.
A new Owl object is created in the main method. The object reference is labeled as its interface, which is okay. The casting on the right side of the assignment operator is legal but redundant because it is upcasting.
In my understanding, because the Owl object reference is labeled as Nocturnal, only the method in the Nocturnal interface is accessible (and no longer the method in the Owl class itself). That is why I would have expected this code to output "true", instead of "false".
How come that the isBlind method from the Owl class is still accessible?
Brecht Geeraerts wrote:In my understanding, because the Owl object reference is labeled as Nocturnal, only the method in the Nocturnal interface is accessible (and no longer the method in the Owl class itself). That is why I would have expected this code to output "true", instead of "false".
Hi Brecht. I'd avoid word "labeled" because I'm not sure it fits well in Java, but I do understand what you mean.
So reference is indeed of an interface Nocturnal type (better word than labeled). That means, that at compile time you can use methods which are declared in the mentioned interface. However, the object at runtime appears to be Owl, that's because is what you instantiated, hence its method is invoked due to polymorphism.
If you'd remove isBlind() from Owl class, code still would compile, because Nocturnal interface has it declared, but during the runtime this time would print what you were expecting from start.
I presume you understand that isBlind() is overriden by Owl class, while Nocturnal interface provides its default implementation (due to "default" keyword used).
Thanks a lot, Liutauras and Darko. I did not know this article existed. It is a well-buried treasure. I will have to read it several times though to really understand it.
I think what confuses me is this: In the above mentioned book, the following is stated: "Once the object has been assigned a new reference type, only the methods and variables available to that reference type are callable on the object without an explicit cast."
So why is the isBlind method of the Owl class still visible to Nocturnal nocturnal?
You are confusing a method declaration with its implementation.
The declarations Nocturnal.isBlind() and Owl.isBlind() have the SAME method signature. Nocturnal just gives a different implementation for it than Owl does.
When you call an instance method, the implementation that is used is ALWAYS the implementation given by the actual runtime type of the object, regardless of the formal type that is used for the variable that refers to the object.
What the book means by the phrase you quoted, is that you can only use method signatures declared in the formal type of the reference that you're calling the method on. Here's an example:
Line 3 demonstrates that you can call isBlind() on a reference with the formal type Nocturnal, because it's declared in Nocturnal. The compiler knows that regardless of what actual kind of nocturnal animal is assigned, it WILL have an isBlind() method. It will still use the implementation given by Owl.
Line 4 demonstrates that you can not call numberOfFeathers() on a reference with the formal type Nocturnal, because it's not declared in Nocturnal. There are nocturnal animals that don't have feathers. The compiler can't determine that the nocturnal variable will never refer to a nocturnal animal that is not an Owl.
Thank you for going through the trouble of elaborating with an example. It is truly appreciated. I had to read it several times to let it sink in, but I think I get it now. It can be quite confusing to beginners (at least in my case it is) :-)
Also a sincere thanks to Liutauras and Darko of course. Putting the different pieces of the puzzle together has paid off.