Quick Java Example, can't figure out why

Discussion in 'Mac Programming' started by Dabisu, Mar 30, 2008.

  1. macrumors member

    Joined:
    Jun 8, 2006
    #1
    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!
     
  2. macrumors 6502a

    Joined:
    Dec 4, 2006
    Location:
    Katy, Texas
    #2
    So, what are you getting? "A-h" or "B-h"?
     
  3. macrumors member

    myawn

    Joined:
    Nov 9, 2006
    Location:
    Marietta, GA
    #3
    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.
     
  4. macrumors newbie

    Joined:
    Oct 2, 2006
    #4
    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.
     
  5. thread starter macrumors member

    Joined:
    Jun 8, 2006
    #5
    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

    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?
     
  6. thread starter macrumors member

    Joined:
    Jun 8, 2006
    #6
    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?
     
  7. thread starter macrumors member

    Joined:
    Jun 8, 2006
    #7
    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!
     
  8. macrumors 6502a

    Joined:
    Dec 4, 2006
    Location:
    Katy, Texas
    #8
    Run time polymorphism, I believe it is called.
     
  9. macrumors newbie

    Joined:
    Oct 2, 2006
    #9
    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!
     
  10. macrumors 6502a

    Joined:
    Sep 3, 2005
    Location:
    Cramlington, UK
    #10
    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:-

    Code:
    ( (B)y ).h( x ) ;
    
    which would print "B-h".

    b e n
     

Share This Page