3
public class A{
    public static int x = 1;
    public int m(A a, B b){
        return a.m(b, b) + x;
    }
}

public class B extends A {
    public int m(A a1, B a2){
        if(a1 == a2)
            return x;
        return super.m(a1,a2);
    }
}

This is a question from a past exam of a subject I am taking.

public class Main{
    public static void main(String[] args){
        B b1 = new B(){int m(A a, A b){ return 10; }};
        System.out.println(b1.m(b1, b1));
    }
}

The question is, what does the following output. I was correct in the answer of 1. But I failed to fully understand why.

Since the inner class of the B object is (A,A). Am i correct in thinking it can not override the super method m since it is (A,B)? Would it be able to override, if the parameters of the two methods were swapped?

Since it can neither override or overload, it does nothing and simply uses the method m in B class?

Does the inner class of the object, only work for itself? Is it like an anon class?

Apologises about all the questions.

Thanks in advance.

Edit:

From my understanding so far, its because the static type is set to B, so the type B is unable to see the anon class. If this was set to public, it would be able to be seen, but it still wouldn't be used.

This confused me on another question.

public class A{
    public static int x = 1;
    public int m(A a, B b){
        return a.m(b, b) + x;
    }
}

public class Main{
 public static void main(String[] args){
  A a1=new A();
  A a2=new A(){ 
   int m(A a,B b){
    return 10;
   }};
  B b1=new B();
  System.out.println(a1.m(a2,b1));
 }
}

When the following is called, the output is 11. When a1.m is called, it passes a2 and b1.

In the A class, when a.m(b,b) is called. It calls the dynamic type. Is this because it changes to the dynamic type once parsed? So now it is able to use the anon class?

user2469515
  • 373
  • 3
  • 12
  • Answer below, please tell me if something is obscure. This is quite some exercise here ;) – fge Jun 12 '13 at 01:32

4 Answers4

6

Let us walk through the JVM:

B b1 = new B(){ int m(A a,A b) { return 10; } };

This creates an instance of B with an anonymous overload of method m() having two arguments of type A. But this is a different m() method than what class B (or A) defines, since their signature (A, A vs A, B) differ.

Then:

System.out.println(b1.m(b1, b1));

This calls b1's m() method with two arguments of type B.

Now the JVM looks up what m() is:

  • there is no method m() having two arguments of type B;
  • in class B, it finds a match: a method by name m() whose first argument is a A (since B inherits A) and a second argument which is of type B;
  • the anonymous overloading by b1 is completely ignored here! (see https://gist.github.com/fge/5762353)
  • end of method lookup.

The m() method of class B is therefore invoked. And in this method, we have:

if (a1 == a2) // TRUE!
   return x;

Since the condition is true (the method has been called with the two arguments being the exact same object references), the value of x must be returned; and x is defined by class A, which class B extends:

 public static int x = 1;

Since this is a static member of class A (which class B does not hide) it is equally accessible by instance methods, from any instance of A or B; therefore, the return code, and output of this program, is 1.

fge
  • 119,121
  • 33
  • 254
  • 329
  • It isn't looking at the method defined within the anonymous inner class because the (static) type of `b1` is `B`. – Tom Hawtin - tackline Jun 12 '13 at 01:34
  • No. Try the sample code with the anonymous overload of `m()` having two arguments of type `B` instead of `A`: the returned value will be 10! Because `B,B` is more specific that `A, B`; but here, the overload is `A, A` which is _less_ specific. – fge Jun 12 '13 at 01:34
  • If it does that, I think there's a bug in javac. (I don't have Java installed on my own machine.) – Tom Hawtin - tackline Jun 12 '13 at 01:46
  • Thanks, but am now stuck on another part. I edited the above post. – user2469515 Jun 12 '13 at 02:53
4

Am i correct in thinking it can not override the super method m since it is (A,B)?

Yes, you are correct: this creates an overload, not an override of the method in the base class.

Would it be able to override, if the parameters of the two methods were swapped?

No: to override, the method signatures must match exactly.

Since it can neither override or overload, it does nothing and simply uses the method m in B class?

Not exactly: the (A, B) overloads happens to be more specific than the (A, A) overload.

Does the inner class of the object, only work for itself? Is it like an anon class?

You would be able to invoke the method in the inner class, had you passed it a pair of As.

Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
1

There are a few points here:

  • The method in the anonymous inner class is not public, so cannot override a public method. Always use @Override if you have to override a non-abstract method.
  • The (static) type of b1 is B, so the extra method declared in the anonymous type is not available. Although you can do things like:

    B b1 = null;
    System.out.println(new B(){int m(B a, B b){ return 10; }.m(b1, b1));
    

Or

    final B b1 = null;
    new B() {
        {
            System.out.println(this.m(b1, b1));
        }
        int m(B a, B b) { return 10; }
    };
  • The language selects the override with the most specific parameters (if it exists), rather than the least specific. Corrected in previous examples. For instance System.err.println("donkey".toCharArray()); does not call println(Object).
  • Overridden methods can relax the return type, "covariant return types" (since 1.5). Not quite the same thing happens for parameters when generic parameter types in the supertype (for instance for Comparable).
Tom Hawtin - tackline
  • 145,806
  • 30
  • 211
  • 305
  • Thanks, that helped me. But raised another question. I edited at the end of the original post. – user2469515 Jun 12 '13 at 02:51
  • @user2469515 Overloading is done statically at compile time on the static type of the variable. Overriding is done dynamically as the method is executed of the type that the variable happens to be pointing to at the time. Some languages allow dynamic dispatch on more than one type (multiple dispatch, or just double dispatch), but there's issues with that. – Tom Hawtin - tackline Jun 12 '13 at 03:01
1

Adding on top of everyone answers. The answers to the following questions should be relevant, especially the one pointing to the JLS (15.12.2.5 Choosing the Most Specific Method) .

Community
  • 1
  • 1
ceilfors
  • 2,617
  • 23
  • 33