• 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

Object construction, and polymorphism

 
Ranch Hand
Posts: 65
7
  • Likes 1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hello all,

Is an object constructed recursively in Java? That is, like:
{Current Class Instance} = {Current Class Field Declarations} + {Super Class Instance}
Where the same definition applies to {Super Class Instance}; we stop when we reach the root (i.e. the Object class).

The reason I'm asking this is because,

1) JLS says,

Whenever a new instance of a class is created (§12.5), a new variable associated with that instance is created for every instance variable declared in that class or any of its superclasses.


2) The subclass does not know about uninherited fields of its superclass.

As for my second question, take a look at my attached image file. Baz.play() does not override Bar.play(), since Baz has no notion of Bar.play() because the latter is not inherited.

So, if I have the following line of code: Foo o = new Baz();
Then o.play() invokes Bar.play(), because Bar.play() overrides Foo.play() and o is a Baz object.

The problem is that I'm used to think of polymorphism in concrete terms, and I can't think of a situation where an overriding method (such as Bar.play()) is not inherited by subclasses. That's why I don't know how polymorphism works generally (or in abstract).

Thank you.
uml.jpg
[Thumbnail for uml.jpg]
 
Ramsin Khoshaba
Ranch Hand
Posts: 65
7
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Okay, this is more complicated than I initially thought.

I just read this. Addressing the second question, there is something called a method table.

A Class object representing a class type has a method table, each entry of which includes a method name and address. So in my example, Bar has a method table with an entry having the inherited method's name (for some reason, it is Foo.play rather than Bar.play) and its address (in this case the address of Bar.play).

Now, I believe that Baz's method table has no entry for Foo.play, because Baz does not inherit Bar.play.

So having,
Foo o = new Baz();
o.play();
How does JVM know to invoke Bar.play? I'm asking this because the method table for the runtime type of o (which is Baz) has no entry for Foo.play. So is it because the JVM looks up in the previous method table?

I'm still not entirely sure though why the entry of Bar's method table stores the name Foo.play (instead of Bar.play).
 
Marshal
Posts: 8857
637
Mac OS X VI Editor BSD Java
  • Likes 1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi,

Before someone steps in, please read a story called "How my Dog learned Polymorphism".
 
Bartender
Posts: 10780
71
Hibernate Eclipse IDE Ubuntu
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Ramsin Khoshaba wrote:So, if I have the following line of code: Foo o = new Baz();
Then o.play() invokes Bar.play(), because Bar.play() overrides Foo.play() and o is a Baz object.


Yes, but if I read your diagram right, and Baz is in a different package to Foo/Bar, then Baz.play() does NOT override Bar.play(), because it does not inherit it, and therefore doesn't "know" about it.

And if you put the @Override annotation on it, you'd get an error - which is why you should ALWAYS use it on methods that you think are overridden.

HIH

Winston

PS: Welcome to JavaRanch, Rasmin!
 
Liutauras Vilda
Marshal
Posts: 8857
637
Mac OS X VI Editor BSD Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Ramsin Khoshaba wrote:So having,
Foo o = new Baz();
o.play();
How does JVM know to invoke Bar.play?

If you were look again to diagram, you'd see, that play() method in Foo and Bar classes has package private access modifier. That means, that you don't override play() method in Baz class.

The code as you wrote wouldn't compile. So in order to execute play() method which is defined in Baz class, you need to cast reference variable to Baz.
In order to run method which is defined in Foo class, you'd need instantiate it with its own implementation.
That is a bit unusual question because of those access modifiers. Such questions more likely to come up in certification exams rather than in practice probably.
 
Ramsin Khoshaba
Ranch Hand
Posts: 65
7
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Liutauras Vilda wrote:The code as you wrote wouldn't compile. So in order to execute play() method which is defined in Baz class, you need to cast reference variable to Baz.


Why not?

o.play() would invoke the method defined in Bar. (Of course, if the invocation occurs inside package a.)

Oh, I forgot to use the fully qualified name of Baz, so

compiles fine and invokes the play() implementation defined in Bar.

I'm aware that play() in Foo is overriden by play() in Bar, and play() in Baz is a separate/unrelated method that happens to have the same signature.
 
Liutauras Vilda
Marshal
Posts: 8857
637
Mac OS X VI Editor BSD Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Ramsin Khoshaba wrote:Oh, I forgot to use the fully qualified name of Baz, so
compiles fine and invokes the play() implementation defined in Bar.


If you managed to mimic situation as in your provided diagram, it shouldn't compile that way, I'm almost for sure. Please show full code you wrote.
 
Winston Gutkowski
Bartender
Posts: 10780
71
Hibernate Eclipse IDE Ubuntu
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Ramsin Khoshaba wrote:Why not?


Because your next assumption - "(Of course, if the invocation occurs inside package a.)" is WRONG.

It makes no difference where the invocation occurs; only whether the class that defines the method supposedly being "overridden" actually inherits it.

Definition (in Java) is static, invocation is done at execution time.

Winston
 
Ramsin Khoshaba
Ranch Hand
Posts: 65
7
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator




 
Ramsin Khoshaba
Ranch Hand
Posts: 65
7
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Winston Gutkowski wrote:

Ramsin Khoshaba wrote:Why not?


Because your next assumption - "(Of course, if the invocation occurs inside package a.)" is WRONG.

It makes no difference where the invocation occurs; only whether the class that defines the method supposedly being "overridden" actually inherits it.

Definition (in Java) is static, invocation is done at execution time.

Winston



Why?

Having Foo (without main()) and Bar as above then,

produces an error because play() in Foo is not visible in package b.
 
Liutauras Vilda
Marshal
Posts: 8857
637
Mac OS X VI Editor BSD Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
You didn't manage to mimic situation as per your diagram.

play method in class Baz should have public access modifier, bu that doesn't change anything anyway.
play method cannot be overriden because of two reasons:
1. Overriden method cannot give broader access modifier than inherited method from its superclass. Can restrict more, but not release visibility.
2. play has a package private access modifier in Bar class which is in package a, and Baz class is in different package.

Now you saying that it runs just fine, I really don't believe that and as I said before, i'm almost for sure i'm right.

Why?

Because refence o is of type Foo, nevertheless it is instantiated with Baz object. So, technically play method should not be visible to reference o because Baz class does not override play method from its inheritance tree.

The only way to execute play method in this scenario (which is a bit unusual) is to execute play method which is from Baz class, and that you could do only by casting reference variable to Baz type.

That would look:
No other options should be allowed in this scenario. Unless I miss something, but someone will correct me soon in case it happened
 
Ramsin Khoshaba
Ranch Hand
Posts: 65
7
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Liutauras Vilda wrote:play method in class Baz should have public access modifier, bu that doesn't change anything anyway.


The plus sign is the UML notation for public access.
Oops, I forgot to put the public modifier before play() in Baz, but I don't think that should matter for what follows.

Liutauras Vilda wrote:Because refence o is of type Foo, nevertheless it is instantiated with Baz object. So, technically play method should not be visible to reference o because Baz class does not override play method from its inheritance tree.


play() in Baz does not override anything, I agree. But reference o of type Foo recognizes the play() method declared inside Foo (not that of Baz). A play() method is declared in Foo, so it is Foo's member. And Foo's play() is overriden by Bar's play() (Baz is not involved here).
 
Liutauras Vilda
Marshal
Posts: 8857
637
Mac OS X VI Editor BSD Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Ramsin Khoshaba wrote:play() in Baz does not override anything, I agree. But reference o of type Foo recognizes the play() method declared inside Foo (not that of Baz). The play() method is declared in Foo, so it is Foo's member. And Foo's play() is overriden by Bar's play() (Baz is not involved here).


I am sorry, but I don't get your point. What is the question and where the confusion arise?

And how that underlined part in quote is related to those two lines you showed us earlier?
 
Ramsin Khoshaba
Ranch Hand
Posts: 65
7
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Liutauras Vilda wrote:

Ramsin Khoshaba wrote:play() in Baz does not override anything, I agree. But reference o of type Foo recognizes the play() method declared inside Foo (not that of Baz). The play() method is declared in Foo, so it is Foo's member. And Foo's play() is overriden by Bar's play() (Baz is not involved here).


I am sorry, but I don't get your point. What is the question and where the confusion arise?

And how that underlined part in quote is related to those two lines you showed us earlier?


Invoking o.play() prints "In Bar" (not "In Foo"), so Bar is related.

I had two questions, the second of which was about how polymorphism works in *general*, i.e. the algorithm involved and why.
I asked the second question because of the two-line example printing "In Bar".
 
Liutauras Vilda
Marshal
Posts: 8857
637
Mac OS X VI Editor BSD Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Ok, I see now. You confusing us by providing diagram and running code which is doesn't fit to what is visualised in diagram. Where the main method came from in your Foo class? Diagram specifies only play method in it. main method doesn't look to be specified anywhere in package a class. That changes game rules.

Look up for similar/same questions in our OCAJP 7/8 certification forum. There is a search field which will help you on that. Similar questions were asked and answered there multiple times.
 
Winston Gutkowski
Bartender
Posts: 10780
71
Hibernate Eclipse IDE Ubuntu
  • Likes 1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Ramsin Khoshaba wrote:

Winston Gutkowski wrote:

Ramsin Khoshaba wrote:Why not?

Because your next assumption - "(Of course, if the invocation occurs inside package a.)" is WRONG.
It makes no difference where the invocation occurs; only whether the class that defines the method supposedly being "overridden" actually inherits it.


Why?


Erm....this seems to be getting cyclic.

Why? Because that's how Java does it. It is a statically-typed Object-Oriented language.

There might be others that don't; although, TBH, I'm not sure what you expect it TO do.

And perhaps that's the problem. Why don't you explain to us how you think it should work - and why - and maybe we'll have a bit more to work with.

I had two questions, the second of which was about how polymorphism works in *general*, i.e. the algorithm involved and why.
I asked the second question because of the two-line example printing "In Bar".


And I have actually answered both. Baz.play() is NOT related to any other play() method, for the reasons I explained.

My advice: Add @Override to that method; and try to compile it. If you DON'T get a error when you do, I'll give you a cow.

Winston
 
Liutauras Vilda
Marshal
Posts: 8857
637
Mac OS X VI Editor BSD Java
  • Likes 1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
I found a similar thread for you. Basically it should clear your doubts. Read this.
 
Ramsin Khoshaba
Ranch Hand
Posts: 65
7
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi,

I think we've deviated from the main questions but anyway.
I looked at that thread and so it made me address another issue I had been having with the protected keyword.

1. protected members:
Assume that S is a subclass of some direct or indirect superclass C. A protected member m declared in C is accessible inside the package in which C is declared, and in S if and only if S is in the same package as A, or the type of the expression or reference-type used to access m is S or a subclass of S.
Am I right? This is difficult.

2. Are objects constructed recursively in Java?
I'm asking this because e.g. a class S has no notion of private fields of its superclass C. And I believe that S 'knows' about its direct superclass. Therefore to construct a S object, S has to construct first a C object; and to do so C has to construct an object of its superclass first; and so on... Like:
{Current Class Instance} = {Current Class Field Declarations} + {Super Class Instance}

3. polymorphism
I was trying to understand polymorphism in every scenario (even not-practical ones). That's why I've been trying to understand the "behavior" of polymorphism. I tried to read a little about method tables, but that's an JVM implementation detail: I think that studying method tables to understand polymorphism is like studying a full-adder circuit to learn addition! I don't want to get as low as implementation details neither as high as Mammal-Dog examples, I want to understand polymorphism at an intermediate level of abstraction, at the "Java level."

Thank you...
 
Liutauras Vilda
Marshal
Posts: 8857
637
Mac OS X VI Editor BSD Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Ramsin Khoshaba wrote:I think we've deviated from the main questions

No, we haven't. Problem that there are few different scenarios for few different problems discussed at the same time.

It seems we all agree, that method play is not being overridden in class Baz. That is clear, right? As Winston suggested earlier, use @Override annotation to prove that to yourself.

Now the other confusions
1. Why the lines below (particularly line 2)
Produces an error at compile time in the case when those are placed somewhere outside class Foo and possibly outside package a.

2. Why the same lines of code do not produce compile time error when those 2 lines appear in the main within the Foo class.

3. And the third confusion arise, why, when those 2 lines compiles as per (2nd point), executes play method which is in Bar class, but not in Foo class.

Please confirm or negate that these are your confusions at the moment?


The thing is, you need to be clear and precise in asking questions. The diagram you provided in your initial post and later you made some assumptions about the code were incorrect and confused us. Because we advised your based on your diagram and we were right I would say in replying what we replied. But you disagreed with us because you had different outcome which we didn't know about (because you were using different scenario), so your written code behaved differently than we mentioned to you it should behave.

Later, I provided you a thread which contains similar question. I had a feeling yesterday before giving away the link to thread that lots of times used word protected in that thread will make you think that is is something specific with protected, but that is not true.
Read once again that thread carefully and in full, don't cut corners, you'll find the reasoning which is common to both problems, yours and that chap's in the other thread.

At least try to think out loud and write down, what you think is happening there? In case you won't find an answer, I might will point out post numbering, which post/-s exactly contains the answer, so you could try once again

If that won't help, I'll kindly ask Roel or Scott or someone else who are active in that forum to help you out, they are an experts on that

 
Ramsin Khoshaba
Ranch Hand
Posts: 65
7
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Liutauras Vilda wrote:It seems we all agree, that method play is not being overridden in class Baz. That is clear, right? As Winston suggested earlier, use @Override annotation to prove that to yourself.


I agree.

Liutauras Vilda wrote:1. Why the lines below (particularly line 2)
Produces an error at compile time in the case when those are placed somewhere outside class Foo and possibly outside package a.


When they are placed outside package a, Foo's member play() is not accessible, because play() has package access. No confusion.

Liutauras Vilda wrote:2. Why the same lines of code do not produce compile time error when those 2 lines appear in the main within the Foo class.


play() is declared in Foo. No confusion.

Liutauras Vilda wrote:3. And the third confusion arise, why, when those 2 lines compiles as per (2nd point), executes play method which is in Bar class, but not in Foo class.


Somewhat confused here, because: I know that play in Bar overrides play in Foo; but how does JVM know that Bar.play should be executed when o's runtime type (that is, Baz) has no member that overrides Foo.play? I've heard that there is some sort of search for an overriding method from the runtime-type and upwards in the inheritance hierarchy, but I'm not sure.

Ok, I will read every post of that thread.

A few months back when I wrote a topic in this forum, I had thought that: members are inherited as if they were newly declared in a subclass. This caused me a lot of confusion for some obvious reasons. Also back then I had had a course in Java and had been told that all members (even private ones) are inherited.

Is there any book about object-orientation that is not-so-beginner-friendly but not as technical as JLS?
 
Ramsin Khoshaba
Ranch Hand
Posts: 65
7
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Ramsin Khoshaba wrote:

Liutauras Vilda wrote:3. And the third confusion arise, why, when those 2 lines compiles as per (2nd point), executes play method which is in Bar class, but not in Foo class.


Somewhat confused here, because: I know that play in Bar overrides play in Foo; but how does JVM know that Bar.play should be executed when o's runtime type (that is, Baz) has no member that overrides Foo.play? I've heard that there is some sort of search for an overriding method from the runtime-type and upwards in the inheritance hierarchy, but I'm not sure.


In addition, I know that for the compiler o.play() refers to Foo.play but Bar.play is called during runtime because of polymorphism.
 
Sheriff
Posts: 7125
184
Eclipse IDE Postgres Database VI Editor Chrome Java Ubuntu
  • Likes 1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Is there any book about object-orientation that is not-so-beginner-friendly but not as technical as JLS?


I've heard Core Java recommended. There is a section on object orientation in it.
 
Liutauras Vilda
Marshal
Posts: 8857
637
Mac OS X VI Editor BSD Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
I also copied this thread to our certification forum, I'm sure you'll get here better help on tricky picky certification questions
 
Ranch Hand
Posts: 182
18
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Ramsin Khoshaba wrote:Somewhat confused here, because: I know that play in Bar overrides play in Foo; but how does JVM know that Bar.play should be executed when o's runtime type (that is, Baz) has no member that overrides Foo.play? I've heard that there is some sort of search for an overriding method from the runtime-type and upwards in the inheritance hierarchy,


This is like Multilevel Inheritance.

'o' is a Foo reference but a Baz object. Dynamic method dispatch is a mechanism by which a call to an overridden method is resolved at runtime.

At runtime the overridden play() in b.Baz() should be invoked. In Baz,play() method is not overridden.But Baz is the Subclass of Bar. Now the subclasses inherit the superclass methods. So Baz inherits the Bar's overridden play() method. play() has a package-private access modifier but because it is being accessed within the same package from the Foo class, there's no trouble in calling the Bar's play() method and prints "In Bar".

my observation is Foo's play() is kind of being shadowed by Bar's play(). If you were to remove Bar's play(), code compiles and now Baz's inherited play() from Foo will be called printing "In Foo".

*Edit - added the missing "Foo", in last sentence.
 
Liutauras Vilda
Marshal
Posts: 8857
637
Mac OS X VI Editor BSD Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Ramya Subraamanian wrote:If you were to remove Bar's play(), code compiles and now Baz's inherited play() from Foo will be called

No, it wouldn't. Because Baz does not override play(), as play() in Bar has package private access modifier, and Baz and Bar are in different packages.

By removing play() in Bar should get executed method play() from Foo (if code gets executed from Foo class).
 
Ramya R Subramanian
Ranch Hand
Posts: 182
18
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
But it compiles.. I meant a code like this. Here Foo's play() will be called.


 
Liutauras Vilda
Marshal
Posts: 8857
637
Mac OS X VI Editor BSD Java
  • Likes 1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
I agree with your current statement and the code you posted

What I quoted from your earlier post, I understood you differently. But maybe you just failed to express yourself clearly, or I just misunderstood you

Ramya Subraamanian wrote:If you were to remove Bar's play(), code compiles and now Baz's inherited play() from Foo will be called

 
Ramsin Khoshaba
Ranch Hand
Posts: 65
7
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
From JLS,

The dynamic lookup process starts from a class S, determined as follows:

  • If the invocation mode is interface or virtual, then S is initially the actual run-time class R of the target object.
  • If the invocation mode is super, then S is initially the qualifying type (§13.1) of the method invocation.

  • The dynamic method lookup uses the following procedure to search class S, and then the superclasses and superinterfaces of class S, as necessary, for method m.

    Let X be the compile-time type of the target reference of the method invocation. Then:

    1.  If class S contains a declaration for a method named m with the same descriptor (same number of parameters, the same parameter types, and the same return type) required by the method invocation as determined at compile time (§15.12.3), then:
  • If the invocation mode is super or interface, then this is the method to be invoked, and the procedure terminates.
  • If the invocation mode is virtual, and the declaration in S overrides X.m (§8.4.8.1), then the method declared in S is the method to be invoked, and the procedure terminates.

  • 2.  Otherwise, if S has a superclass, the lookup procedure of steps 1 and 2 is performed recursively using the direct superclass of S in place of S; the method to be invoked, if any, is the result of the recursive invocation of this lookup procedure.

    3.  If no method is found by the previous two steps, the superinterfaces of S are searched for a suitable method.


    I confess that I don't understand everything here; I don't know what a mode really is for example; but anyway.

    So here is how I think:

    Before I start, I want to make sure that we're following the same code,




    Basically,

    compiles because Foo is a super class of Baz, and Foo has a member method, namely play(). play() in Bar overrides play() in Foo, but play() in Baz does NOT override any method. So, the code above prints "In Bar" but why?

    If X is Foo and S is Baz, the runtime type of o; then:
    The dynamic lookup process starts from Baz and searches for a method denoted by m with the same descriptor as that of play() in Foo such that m overrides play() in Foo. The lookup cannot find such a method, so it continues to search in Bar (the direct super class of Baz) and there the process finds a method with the same descriptor that overrides play() in Foo. Therefore, the implementation given in Bar is invoked, that's why "In Bar" is printed.


    run:
    In Bar
    BUILD SUCCESSFUL (total time: 0 seconds)

     
    Liutauras Vilda
    Marshal
    Posts: 8857
    637
    Mac OS X VI Editor BSD Java
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    Cow for you. For finding relevant part in JLS and for cracking things out for yourself. Well done
     
    Winston Gutkowski
    Bartender
    Posts: 10780
    71
    Hibernate Eclipse IDE Ubuntu
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator

    Ramsin Khoshaba wrote:The dynamic lookup process starts from Baz


    I don't think that's correct. If it started from Baz, it would find Baz.play() immediately and use that, since it meets all the criteria for the method call, but it doesn't.

    Look at the declaration:
      Foo o = new Baz();
    Now you and I both know that o is actually a Baz, because we're smart and we can see it; but as far as the compiler (which is stupid) is concerned, it's a Foo, because we told it that it is.

    There are TWO types in play here:
    1. The "declared" type - which is Foo.
    2. The "run-time" type - which is Baz.
    and the compiler is ONLY concerned with declared types.

    What happens at execution time - which is when the method actually gets "found" - is a bit different. It still starts at the declared type (Foo), but it searches downwards for the most specific version of the method (in this case play()), based on the object's runtime type (Baz). And that search only includes methods that override Foo.play().

    And since - as I hope you now understand - Baz.play() does NOT override Bar.play(), the most specific method it finds is Bar.play(), so that's what it executes.
    The effect is the same as you describe, but the mechanics are not; so it's worth understanding them just in case there are cases where they differ.

    And just as a little aside for you: One of the classic mistakes made by beginners is the following:They then get very surprised when two objects that they expect to be "equal" aren't (usually when they try to put them in a collection).

    And the reason is very simple: the method above does NOT override Object.equals(), which is declared as:
      public boolean equals(Object obj) { ...

    And again, if you used @Override, you would get an error when you tried to compile it.

    So my advice: remember about @Override. It is your friend.

    Winston
     
    Marshal
    Posts: 79179
    377
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator

    Winston Gutkowski wrote:. . . and the compiler is ONLY concerned with declared types. . . . Winston

    If you look at this sort of code you can see why:-The runtime type of that reference is completely unknown before the code is executed.
     
    Ramsin Khoshaba
    Ranch Hand
    Posts: 65
    7
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator

    Winston Gutkowski wrote:What happens at execution time - which is when the method actually gets "found" - is a bit different. It still starts at the declared type (Foo), but it searches downwards for the most specific version of the method (in this case play()), based on the object's runtime type (Baz). And that search only includes methods that override Foo.play().


    I agree with most of what you said, except that it searches downwards. Because I don't see how this agrees with JLS 15.12.4.4, unless I have misunderstood JLS.

    Just for preparation, from JLS 15.12.3


    The invocation mode, computed as follows:

    If the qualifying type of the method declaration is a class, then:

  • If the compile-time declaration has the static modifier, then the invocation mode is static.
  • Otherwise, if the compile-time declaration has the private modifier, then the invocation mode is nonvirtual.
  • Otherwise, if the part of the method invocation before the left parenthesis is of the form super . Identifier or of the form TypeName . super . Identifier, then the invocation mode is super.
  • Otherwise, the invocation mode is virtual.

  • If the qualifying type of the method invocation is an interface, then the invocation mode is interface.


    So in our case, we are concerned with the invocation mode that is virtual.

    If you reread the section of JLS 15.12.4.4 that I posted in my previous post, then you'll see that the search is upwards (unless I've misunderstood the JLS).

    And note the use of and in JLS. The word is used more strongly here, than in conversations.


  • If the invocation mode is virtual, and the declaration in S overrides X.m (§8.4.8.1), then the method declared in S is the method to be invoked, and the procedure terminates.

  •  
    Winston Gutkowski
    Bartender
    Posts: 10780
    71
    Hibernate Eclipse IDE Ubuntu
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator

    Ramsin Khoshaba wrote:If you reread the section of JLS 15.12.4.4 that I posted in my previous post, then you'll see that the search is upwards (unless I've misunderstood the JLS).]


    No, I think you've understood it just fine. ... Probably better than me in fact. So have a cow.

    However, it does say a bit further on (admittedly in very small print):
    "The dynamic lookup process, while described here explicitly, will often be implemented implicitly, for example as a side-effect of the construction and use of per-class method dispatch tables, or the construction of other per-class structures used for efficient dispatch."

    And it's the "dispatch" part of the process that is usually implemented downwards - or at least used to be.
    It is true, however, that in order to ensure it takes the correct path, the JVM first has to work upwards in order to know which classes are part of the hierarchy from D (the "defined" class) down to R (the "runtime" class).

    However, whenever you're in doubt - or you get conflicting information - always go with the JLS.

    And sorry if I caused any confusion.

    Winston
    reply
      Bookmark Topic Watch Topic
    • New Topic