• 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 Pie Elite all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Jeanne Boyarsky
  • Ron McLeod
  • Paul Clapham
  • Liutauras Vilda
Sheriffs:
  • paul wheaton
  • Rob Spoor
  • Devaka Cooray
Saloon Keepers:
  • Stephan van Hulst
  • Tim Holloway
  • Carey Brown
  • Frits Walraven
  • Tim Moores
Bartenders:
  • Mikalai Zaikin

Java polymorphism confusion

 
Greenhorn
Posts: 3
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
What is going on with ? Is z an X or a Y? Because if i add other methods to X I see that z can call these methods, but if I add additional methods to Y, z cannot call them. However, calling z.method(0) calls the method of Y which is strange. I think late binding has something to do with this. But isn't z upcasted to X and should therefore call X's method? I'm confused.

 
Java Cowboy
Posts: 16084
88
Android Scala 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
Let's be precise here, so you understand exactly what's going on.

First: z is a variable, not an object. A variable is a reference to an object (like a pointer in C or C++).

Variables have a type. The type of the variable z is X. This means that z looks like an X to the compiler: you can call whatever methods are accessible from type X or its supertypes.

If you do X z = new Y();, then z actually refers to an object of type Y. But because the type of the variable is X, you can't access the extra methods that are only in class Y.

Why is this useful? To explain that, it's easier to look at types with less abstract names than 'X' and 'Y'. So, let's look at: List<String> list = new ArrayList<>();

'list' looks like a List to the compiler. You can do everything with it that you can do with a List. That you used a specific implementation of List (namely, ArrayList) isn't important for the rest of the application. In fact, maybe you'd want to change it to a different implementation later. If you want to do that, you only have to change the line to: List<String> list = new LinkedList(); (for example). To the rest of the program, 'list' still looks like a List. That there's now a different implementation behind it (LinkedList instead of ArrayList) isn't something the rest of the program needs to know.

Note that inheritance implies an "is a" relationship. So, if Y extends X, that means that an Y is an X (or, more specifically: an Y is a special kind of X). For example, an ArrayList is a List, and a LinkedList is also a List.

More about inheritance: You can see an object as an onion, with layers, where each layer is a level of inheritance, which adds extra stuff to the object. So, an Y object consists of a core (java.lang.Object), and then the layer added by class X, and finally the layer added by class Y. When you create a new Y object, then the object is created "from the inside out". So, first the constructor of class java.lang.Object is called, then the constructor of X, then the constructor of Y - and then you have a complete Y object.

When you have a variable z of type X, then through that variable you an only see the X part and the java.lang.Object part of the object. The Y layer is "hidden", except for the fact that class Y can override methods in the lower layers. When you call a method on the object that is overridden by class Y, then the Y version of the method is called, even though the variable is of type X. That feature is called "late binding" (the actual method to call is looked up at runtime, from the actual type of the object, rather than at compile time, via the type of the variable).
 
Marshal
Posts: 79179
377
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Jesper de Jong wrote:. . . So, let's look at: List<String> list = new ArrayList<>();

'list' looks like a List to the compiler. You can do everything with it that you can do with a List. That you used a specific implementation of List (namely, ArrayList) isn't important for the rest of the application. . . .

That is a good example; as you will remember Jesper, ArrayList has two methods which are not in the List interface: this one and this one. Because you declared the List as List, you cannot simply use those two methods in an ArrayList.
 
Jesper de Jong
Java Cowboy
Posts: 16084
88
Android Scala IntelliJ IDE Spring Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Yes, ArrayList has a few extra methods beyond the methods declared in interface List.

If your program needs to use those methods, you'll have to declare your variable explicitly as ArrayList, for example: ArrayList<String> list = new ArrayList<>();

In that case my remark "that you used a specific implementation of List (namely, ArrayList) isn't important for the rest of the application" doesn't hold anymore. But that also means that you can't easily change the type to another implementation of List (such as LinkedList).
 
Campbell Ritchie
Marshal
Posts: 79179
377
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
…Or you end up casting your List to ArrayList, which is by no means an ideal solution. It is error‑prone and brittle; we have discussed it elsewhere and you could search for such discussion if you want to know more.
 
Don't get me started about those stupid light bulbs.
reply
    Bookmark Topic Watch Topic
  • New Topic