GeeCON Prague 2014*
The moose likes Java in General and the fly likes I just destroyed Polymorphism Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login


JavaRanch » Java Forums » Java » Java in General
Bookmark "I just destroyed Polymorphism" Watch "I just destroyed Polymorphism" New topic
Author

I just destroyed Polymorphism

Dan Kempten
Greenhorn

Joined: Dec 26, 2008
Posts: 25

This is one for the theorists :

Very simple :

I have two classes, Top and Bottom
Bottom is a subclass of Top
Bottom overrides the method int foo()


BUT ! in the parent, int foo() has default access (package)
in the subclass I have it public int foo() with public access

now..I have the class Goof :


Goof is in the same package as Top,

now the overridden function foo() is defined not by the
class of the reference variable, but from the class Bottom in
this case.

Right?

So I should see top 20 the Bottom class definition of foo()
and bottom 20 the Bottom class definition of foo()

Right? That's what polymorphism says.

however with Goof.class in the same package /top
I get :

top 10
bottom 20

default access of the int foo() in Top class makes
polymorphism no longer valid.

Right?
David Kilcy
Greenhorn

Joined: Aug 25, 2009
Posts: 20
When I ran the code I got 20 for both top and bottom.
You made a mistake somewhere.

Ernest Friedman-Hill
author and iconoclast
Marshal

Joined: Jul 08, 2003
Posts: 24187
    
  34

David is right, the code should give 20/20. But I suppose it's possible that you're using a compiler which gets this wrong. For the sake of argument, then, tell us what you're using to compile and run this?


[Jess in Action][AskingGoodQuestions]
David Kilcy
Greenhorn

Joined: Aug 25, 2009
Posts: 20
Ernest made a good point.
I am using the Sun JDK 1.6 compiler
Henry Wong
author
Sheriff

Joined: Sep 28, 2004
Posts: 18874
    
  40

Just ran this on Eclipse... it complained (warning) about method not being overridden due to package access issues.

When I tried the "@Override" annotation, it failed to compiled.

When I ran it without the annotation, I got 10 and 20.

Henry


Books: Java Threads, 3rd Edition, Jini in a Nutshell, and Java Gems (contributor)
Ernest Friedman-Hill
author and iconoclast
Marshal

Joined: Jul 08, 2003
Posts: 24187
    
  34

OK, I tried running it, and I get 10/20 too, no warnings (1.6.0_15 on Mac OS X).

Hmmm. I suppose the Eclipse warning is the key to what's going on. Because the Top foo() method is hidden from Bottom, the like-named method does not override it; Top.foo() and Bottom.foo() are entirely unrelated methods. If Top.foo() were private, exactly the same thing would happen, for exactly the same reason (you'd have to move main() into Top, of course) but then it wouldn't be so surprising.
Ireneusz Kordal
Ranch Hand

Joined: Jun 21, 2008
Posts: 423
Ernest Friedman-Hill wrote:

Hmmm. I suppose the Eclipse warning is the key

@Override is not the Eclipse warning, this is Java warning; http://java.sun.com/j2se/1.5.0/docs/api/java/lang/Override.html
This warning says that the method that you intent to override in a subclass, does not exist in a parent class.
You didn't show us your second code, probably you have mistake in the name of method.
Steve Luke
Bartender

Joined: Jan 28, 2003
Posts: 4181
    
  21

From the JLS:


8.4.8.1 Overriding (by Instance Methods)

An instance method m1 declared in a class C overrides another instance method, m2, declared in class A iff all of the following are true:
C is a subclass of A.
The signature of m1 is a subsignature (§8.4.2) of the signature of m2.
Either
m2 is public, protected or declared with default access in the same package as C, or
m1 overrides a method m3, m3 distinct from m1, m3 distinct from m2, such that m3 overrides m2.
Moreover, if m1 is not abstract, then m1 is said to implement any and all declarations of abstract methods that it overrides.


Top#foo() is not public, protected, or declared with default access in the same package as Bottom. therefore Bottom#foo() does not override Top#foo(). So when you call top.foo() and Top#foo() is visible to the caller, Top#foo() gets called. I didn't find anywhere in the JLS that states that, given two visible methods for a type in scope which one will be called but it makes sense the one would be the reference-type method, but I can't find documentation to back me up.


Steve
Ernest Friedman-Hill
author and iconoclast
Marshal

Joined: Jul 08, 2003
Posts: 24187
    
  34

Ireneusz Kordal wrote:
@Override is not the Eclipse warning, this is Java warning;


It really burns my butt to be "corrected" by folks who haven't even bothered to read a whole thread. Henry indeed reports that Eclipse -- which has its own Java compiler, and doesn't use the JDK one -- gives a warning for the case in which an attempted override fails because of visibility issues. javac doesn't warn about this -- it just compiles the code without remark.

Of course the @Override error is part of the Java spec. That's the whole point of @Override. I will try not to get too angry at your presumption here.

As for the "mistake in the name of the method", if you'd actually read this thread, I don't think you'd be making that comment either.
Steve Luke
Bartender

Joined: Jan 28, 2003
Posts: 4181
    
  21

Steve Luke wrote:...
So when you call top.foo() and Top#foo() is visible to the caller, Top#foo() gets called. I didn't find anywhere in the JLS that states that, given two visible methods for a type in scope which one will be called but it makes sense the one would be the reference-type method, but I can't find documentation to back me up.


Okay, I think I put it together, in the Method Invocation Expression section of the JLS:

15.12.1 Compile-Time Step 1: Determine Class or Interface to Search

The first step in processing a method invocation at compile time is to figure out the name of the method to be invoked and which class or interface to check for definitions of methods of that name. There are several cases to consider, depending on the form that precedes the left parenthesis, as follows:
- If the form is MethodName, then there are three subcases:
- - If it is a simple name, that is, just an Identifier, then the name of the method is the Identifier. If the Identifier appears within the scope (§6.3) of a visible method declaration with that name, then there must be an enclosing type declaration of which that method is a member. Let T be the innermost such type declaration. The class or interface to search is T.
- - If it is a qualified name of the form TypeName . Identifier, then the name of the method is the Identifier and the class to search is the one named by the TypeName. If TypeName is the name of an interface rather than a class, then a compile-time error occurs, because this form can invoke only static methods and interfaces have no static methods.
- - In all other cases, the qualified name has the form FieldName . Identifier; then the name of the method is the Identifier and the class or interface to search is the declared type T of the field named by the FieldName, if T is a class or interface type, or the upper bound of T if T is a type variable.

So with top.foo(), the class to call the method on is the declared type of top, which is Top.


15.12.4 Runtime Evaluation of Method Invocation

...
15.12.4.4 Locate Method to Invoke

The strategy for method lookup depends on the invocation mode.
...
Otherwise, the invocation mode is interface, virtual, or super, and overriding may occur. A dynamic method lookup is used.

In this case, the invocation mode is virtual, since it is neither called on an interface or via a super. call.
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. This is true even if the target object is an array instance. (Note that for invocation mode interface, R necessarily implements T; for invocation mode virtual, R is necessarily either T or a subclass of T.)
- If the invocation mode is super, then S is initially the qualifying type (§13.1) of the method invocation.

So we start looking for a version of Top#foo() in the runtime type of top, which is Bottom.

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

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

- If class S contains a declaration for a non-abstract 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 (§8.4.8.1) X.m, then the method declared in S is the method to be invoked, and the procedure terminates.

We might think that this means that Bottom#foo() should be called, because it shares th same descriptor as Top#foo(). But, as noted in my last post Bottom#foo() does not override Top#foo() because Top#foo() is not visible to Bottom. So this rule fails.

- - Otherwise, if S has a superclass, this same lookup procedure is performed recursively using the direct superclass of S in place of S; the method to be invoked is the result of the recursive invocation of this lookup procedure.

Which brings us back to executing Top#foo().


I get the output
top 10
bottom 20
when compiled and run from both javac/java version 1.6.0_16 and inside Eclipse.
Dan Kempten
Greenhorn

Joined: Dec 26, 2008
Posts: 25
Hello all,

I didn't realise this would unleash such a fury. But thank you all for your input.

FYI I have been using Java 1.6 and Netbeans to create the whole spiel.

I find this all very fascinating because I will be taking my SCJP in about 6 days.

In about 12 hours I'll get back to this thread and give it a try on Eclipse.
Dan Kempten
Greenhorn

Joined: Dec 26, 2008
Posts: 25
I just tried it out in Eclipse Europa.
Same 10/20 result.
And I tried the @Override annotation and got a good little message when it didn't compile :

This method isn't overriding the superclass method because :

the superclass method is private to a different package

So the method is not really overridden and polymorphism doesn't apply.

Very interesting. Thanks to Steve Luke and the others.
 
GeeCON Prague 2014
 
subject: I just destroyed Polymorphism