PDA

View Full Version : Quick Java Example, can't figure out why




Dabisu
Mar 30, 2008, 06:30 PM
Why does this code output "A-h" instead of "B-h"?

class A {
public void f(){ System.out.println("A-f"); }
public static void g() { System.out.println("A-g"); }
public void h(A x){ System.out.println("A-h"); }
}
class B extends A {
public void f() { System.out.println("B-f"); }
public static void g() { System.out.println("B-g"); }
public void h(B x){ System.out.println("B-h"); }
}

public class Sample5 {
public static void main(String[] args) {
B x = new B();
A y = x;

y.h(x);


} }

Here's what my thought process. At compile time, it checks in the declared type A if there is a function that matches the signature, and because x is of type B, a subtype of A, then there is no compile error. Then at runtime, it will look in the object it is referring to. It refers to object x, and then it looks in B for the method, and it finds B's h(x). That's why I keep getting "B-h".

Does anyone know what I'm missing? I followed these rules for every other example and got it correct, except for this one.

If anyone can help at all, it'd be greatly appreciated!



toddburch
Mar 30, 2008, 06:55 PM
Why does this code output "A-h" instead of "B-h"?
.....
That's why I keep getting "B-h".


So, what are you getting? "A-h" or "B-h"?

myawn
Mar 30, 2008, 06:59 PM
For a definitive answer, you should go right to the spec

http://java.sun.com/docs/books/jls/third_edition/html/expressions.html#15.12.4.4

Not exactly light reading, but if I read it correctly it is saying that it's going to look at the compile-time type of your target (which is A) and if there is a matching method there (matching parameter list, accessible, etc) then it will be called. Since there is a match in A, that's what will get called.

It also indicates that if there is not a match in A, it will then look at superclasses of A (not subclasses, so it seems it would never search B).

My own recollection of this was that the runtime type would take precedence for resolving an instance method, and the compile time type would take precedence for a class (static) method, but if I'm reading the spec correctly that doesn't seem to be what it is saying.

jbruce2112
Mar 30, 2008, 07:12 PM
class A {
public void f(){ System.out.println("A-f"); }
public static void g() { System.out.println("A-g"); }
public void h(A x){ System.out.println("A-h"); }
}
class B extends A {
public void f() { System.out.println("B-f"); }
public static void g() { System.out.println("B-g"); }
public void h(B x){ System.out.println("B-h"); }
}

public class Sample5 {
public static void main(String[] args) {
B x = new B();
A y = x;

y.h(x);


} }

Here's my two cents....

Since B inherits the h(A x) method from A, and it also has a method of it's own that is void h(B x), it overloads it. As far as overloading goes, I believe at compile time, the DECLARED TYPE (reference type) determines which method is to be called. So it goes to the A method, and since it takes an A object, B is guaranteed to do anything A can do, since it inherits it's methods. The JVM invokes A's h(A x) method putting a B object into it.

Dabisu
Mar 30, 2008, 07:19 PM
Thanks, I'm really glad I'm getting some responses.

Basically, here is the whole example I was looking at. At first I only included the one giving me trouble.

Here is the whole list of function calls, with the corresponding output.

x.f(); B-f
y.f(); B-f
B.g(); B-g
A.g(); A-g
x.h(x); B-h
x.h(y); A-h
y.h(x); A-h
y.h(y); A-h


Not exactly light reading, but if I read it correctly it is saying that it's going to look at the compile-time type of your target (which is A) and if there is a matching method there (matching parameter list, accessible, etc) then it will be called. Since there is a match in A, that's what will get called.


If what you were saying is correct, then shouldn't y.f() produce "A-f". This is why it's so confusing.

I'm applying this method to figure the output out. At compile time, it checks declared type if it's in the declared type class, no compile time error. Then at runtime it will just call the method that it is referring to. I was able to get the correct output for EVERYTHING, but y.h(x).

It must have something to do with parameter, no?

Dabisu
Mar 30, 2008, 07:24 PM
Here's my two cents....

Since B inherits the h(A x) method from A, and it also has a method of it's own that is void h(B x), it overloads it. As far as overloading goes, I believe at compile time, the DECLARED TYPE (reference type) determines which method is to be called. So it goes to the A method, and since it takes an A object, B is guaranteed to do anything A can do, since it inherits it's methods. The JVM invokes A's h(A x) method putting a B object into it.

So you're saying if a method is overloaded, rather than overridden, it calls the one determined at compile time as opposed to dynamic binding?

Dabisu
Mar 30, 2008, 08:46 PM
It turns out jbruce was right! I found some old notes of mine and it turns out that overloaded methods are determined at compile-time, while overridden ones are determined at run-time!

Thanks for everyone's input and help!

toddburch
Mar 30, 2008, 09:04 PM
Run time polymorphism, I believe it is called.

jbruce2112
Mar 31, 2008, 12:19 AM
Run time polymorphism, I believe it is called.

yessir. an easy way i use to keep this straight (and seperate from overriding) is that when you overload a method, you are basically just making a brand new method - so that's the compiler's job to sort it out. when you override a method, that's when polymorphism can come into play and confuse you - and polymorphism takes place at runtime.

i don't know if that makes it easier, maybe just repeating it over and over again!

lazydog
Mar 31, 2008, 07:40 AM
Hi

Hope this helps a bitů

The method h() isn't virtual because it has different signatures in A and the derived class B. Object y is cast as an A and so A's h() method will be called. Since object y is initialised with a derived class of A it would be okay to do the following though:-


( (B)y ).h( x ) ;


which would print "B-h".

b e n