• Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Paul Clapham
  • Jeanne Boyarsky
  • Ron McLeod
  • Tim Cooke
Sheriffs:
  • Devaka Cooray
  • paul wheaton
  • Mark Herschberg
Saloon Keepers:
  • Tim Moores
  • Tim Holloway
  • Stephan van Hulst
  • Frits Walraven
  • Jj Roberts
Bartenders:
  • Carey Brown
  • salvin francis
  • Piet Souris

Beginner question about polymorphism

 
Rancher
Posts: 261
12
IntelliJ IDE Spring Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Dear all,

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?

Many thanks,
Brecht




 
Sheriff
Posts: 7942
548
Mac OS X VI Editor BSD Linux
  • Likes 1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

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).
 
Ranch Hand
Posts: 60
1
  • Likes 2
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hey if you are struggling with polymorphism I suggest you check out the ranch version here, helped me a lot. Cheers
 
Liutauras Vilda
Sheriff
Posts: 7942
548
Mac OS X VI Editor BSD Linux
  • Likes 1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Darko Jakimovski wrote:Hey if you are struggling with polymorphism I suggest you check out the ranch version here, helped me a lot. Cheers


Really well article. Have a cow for reminding us.
 
Brecht Geeraerts
Rancher
Posts: 261
12
IntelliJ IDE Spring Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
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?
 
Saloon Keeper
Posts: 12723
277
  • Likes 2
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
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.
 
Brecht Geeraerts
Rancher
Posts: 261
12
IntelliJ IDE Spring Java
  • Likes 1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Dear Stephan,

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.

 
Greenhorn
Posts: 10
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Some points that might help:
- the methods that you can call are based solely on the reference type  e.g. Nocturnal n = new Owl(); // the methods you can call are based on Nocturnal
     - this is done at compile time
- the code that is executed (assuming instance i.e. non-static methods) is determined at runtime polymorphically by the object type e.g. Nocturnal n = new Owl().
    - therefore, the Owl() version of isBlind() is executed.


Regards,
Seán.

PS. If interested, I have a lot of free videos up on my YouTube channel that may help  https://www.youtube.com/channel/UC47bUeEug64OqfM42EBVPRA. If you would like a particular topic covered, let me know.

 
Marshal
Posts: 72059
312
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Welcome to the Ranch
Don't say “reference type”; that means something different. I think you meant to say, “declared type.”

What do your videos say about the basics of object‑oriented design?
 
Seán Kennedy
Greenhorn
Posts: 10
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi Campbell,
   Thanks for the welcome! Would you mind giving me an example of the difference? I always believed the reference was always on the left of the assignment...

Thanks Seán.
 
Campbell Ritchie
Marshal
Posts: 72059
312
  • Likes 2
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
The process for choosing methods is exactly as you wrote, including the part about static methods being bound at compile time and not being overridden.
The Java® Language Specification (=JLS) defines two kinds of datatype: (the eight) primitive types and reference types. The two are handled differently; the memory location for a primitive contains its actual value and the memory location for a reference type contains a pointer or a handle to the actual object in memory. A pointer is a number allowing the runtime to calculate the true memory location and a handle points to a memory location where a pointer can be found. [The chip might use direct and indirect indexing to handle pointers and handles respectively.] Unlike C/C++, Java® doesn't provide any means of finding the actual value of pointers and handles; they are completely hidden behind the reference. You can find the gory details in such sources as Mala Gupta's Java12 book (Packt), but only people who write compilers or update and maintain the JRE actually need such information. When you use any reference type, including arrays, there is always either an object or null behind the reference. Bruce Eckel, in Thinking in Java (3/e, 2006) says that null is implemented by giving the reference the value zero. A primitive datatype may contain zero, but that evaluates to a “real” value, viz. zero (or for a boolean, it means false). So “reference type” means any type that is implemented by creating an object.
A reference is declared with a type, which is its declared type. which is usually written just to the left of the variable's identifier. It may be initialised or assigned to with a different type. Let's see if I can find an example:-or evenAs you said, the compiler uses the declared type to decide which methods are available, and that is called early binding or (maybe better) compile‑time binding, or, rarely, static binding. Eckel says that is why static methods are called static. I don't call that polymorphism myself.
The runtime uses the type the object was created from which is called its runtime type to decide which version of the method to call, which is called late binding or (maybe better) runtime binding. You might call that dynamic binding but I hardly ever hear that term. You don't know whether that was an Owl or a Bat until runtime. And just as you said, that only applies to instance methods. Yes, I do call that polymorphism.In theory, you will find the method eventually because the compiler has verified its presence. If you don't, you will suffer an exception. If you go through the java.base/java.lang package summary and scroll down to “exceptions” and “errors”, you will find the sort of exceptions you might suffer in those circumstances. Challenge: work out how to bamboozle the compiler and get that sort of exception thrown.
 
Stephan van Hulst
Saloon Keeper
Posts: 12723
277
  • Likes 1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Seán Kennedy wrote:Would you mind giving me an example of the difference? I always believed the reference was always on the left of the assignment...


The declared type of a variable, or the declared return type of a method or operator, are what we call an expression's "formal type". It's the type that the compiler definitely knows an expression has. At runtime, an object that such an expression refers to may have a different type than the formal type. It may be of a subtype of the formal type. We call that the expression's "actual type". The compiler usually doesn't know what the actual type of an expression will be.

Both the formal type and the actual type may be "reference types": Expressions of a reference type refer to objects. This is in contrast to primitive types, such as int and boolean, that don't refer to objects at all.

In the above snippet of code, the formal type of the owl variable is Nocturnal, but the actual type of the object it references is Owl. Both types are reference types.

In this snippet of code, the formal type of the degreesCelcius variable is double. The actual type is double as well, because primitive types aren't polymorphic. The int is converted to double before it is assigned. double is not a reference type.
 
Campbell Ritchie
Marshal
Posts: 72059
312
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
I think we all agree, except about what you call things.
 
Seán Kennedy
Greenhorn
Posts: 10
  • Likes 1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi Campbell/Stephan,
   Thanks you so much for taking the time to clarify and provide extensive examples. Hopefully this is now more accurate - "this is a reference variable (non primitive) and the methods we can call using this reference are based on its declared/formal type". So, Nocturnal n = new Owl(); // n is the reference *variable*, Nocturnal is its declared/formal type and Owl is the actual object. Both Nocturnal and Owl are reference types as they are not primitive types.

Thanks again,
Seán.

PS. Sorry Campbell for editing the post. I fully understand that "context" must be maintained otherwise, as you say responses would look incorrect.
 
Campbell Ritchie
Marshal
Posts: 72059
312
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Seán Kennedy wrote:. . . Thanks you . . . Thanks . . .

That's a pleasure

Sorry . . .

Apology accepted
Yes, what you wrote is correct.

Have you seen that the JLS writes about “constant variables”?
 
Seán Kennedy
Greenhorn
Posts: 10
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Have you seen that the JLS writes about “constant variables”?  

. Yikes!
 
Campbell Ritchie
Marshal
Posts: 72059
312
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
They got several years for GBH: to the English Language
 
Greenhorn
Posts: 2
Firefox Browser Opera Chrome
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Thanks guys! This made things clearer also for me
 
Ranch Foreman
Posts: 219
8
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

The process for choosing methods is exactly as you wrote, including the part about static methods being bound at compile time and not being overridden.



Are inherited final methods also subject to early compile-time binding?  That was my thought....a detail, but at some point I am going to come back to Java certification....
 
Stephan van Hulst
Saloon Keeper
Posts: 12723
277
  • Likes 1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
I'm not sure if they are, it might be dependent on the JVM implementation. I imagine that as a performance enhancement, final methods are indeed called statically rather than through a jump table, but only if you call them through an object reference with a formal type of which it is certain that the method is final.

You can probably figure it out by writing a method that calls a final method and then decompiling the bytecode. If final methods behave like private methods, they will be called using invokespecial. If they behave like other instance methods, they will be called using invokevirtual.

You really shouldn't have to know this for any certifications though.
 
Jesse Silverman
Ranch Foreman
Posts: 219
8
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Stephan van Hulst wrote:I'm not sure if they are, it might be dependent on the JVM implementation. I imagine that as a performance enhancement, final methods are indeed called statically rather than through a jump table, but only if you call them through an object reference with a formal type of which it is certain that the method is final.

You can probably figure it out by writing a method that calls a final method and then decompiling the bytecode. If final methods behave like private methods, they will be called using invokespecial. If they behave like other instance methods, they will be called using invokevirtual.

You really shouldn't have to know this for any certifications though.



You are right that it shouldn't be on Certification Exams...everything I write below is outside the scope of Beginning Java for sure, and probably(?) the OCJP.

I was reading this today tho:
https://source.android.com/devices/tech/dalvik/improvements#class-hierarchy-analysis

It is specific to Android, but exactly the stuff I was thinking about...the optimizations can probably only take place in the cases you mentioned, but who knows, they have a pretty smart optimizer...when I look at that section I realize that a super-smart optimizer is a big part of why things are running on our phones much FASTER than possible -- it is much faster than possible without pulling all sorts of tricks that classical Java/JVM stuff never did and seems beyond the scope of what a production optimizer running on production equipment would have been expected to do by someone who learned their stuff for the first time in the 80's -- they are doing some wild stuff!

This kind of stuff is currently work-related for me now for the first-time -- I'd never done anything in the Android Sphere for work....

I came to look at this because there were references to JIT-ing that I thought were errors because modern Android now uses AOT compiling for Java -- it turns out the real picture is complicated, beautiful and terrible, compared to what I imagined based on how we used to run Java long ago.
 
The problems of the world fade way as you eat a piece of pie. This tiny ad has never known problems:
the value of filler advertising in 2021
https://coderanch.com/t/730886/filler-advertising
reply
    Bookmark Topic Watch Topic
  • New Topic