views:

114

answers:

5

This is another of those SCJP questions. The code below prints Alpha:fooBeta:fooBeta:barBeta:bar, and I don't understand why the first foo call picked Alpha's foo instead of Beta's. If the Alpha.foo parameter is changed to String instead of String..., then the output is Beta:fooBeta:fooBeta:barBeta:barwhich makes sense.

My understanding is that when you say Alpha a = new Beta();, the compiler checks for Alpha.foo, but the JVM will actually run Beta.foo. For one thing, Beta does have a foo method whose signature matches the call. For another, I thought varargs methods only run when there's no other method available that matches the call. So that's two reasons I think Alpha.foo shouldn't be run. What part of this understanding is wrong?

Thanks!

class Alpha {

    public void foo(String... args) { //if this were String args, then it makes sense
        System.out.print("Alpha:foo");
    }

    public void bar(String a) {
        System.out.print("Alpha:bar");
    } }

public class Beta extends Alpha {

    public void foo(String a) {
        System.out.print("Beta:foo");
    }

    public void bar(String a) {
        System.out.print("Beta:bar");
    }

    public static void main(String[] arg) {
        Alpha a = new Beta();
        Beta b = (Beta) a;
        a.foo("test");//confusing line
        b.foo("test");
        a.bar("test");
        b.bar("test");
    } }

Edit: I think I know where I misunderstood things now. I thought that in a SuperClass sc = new SubClass(); situation, whatever method is called on sc will be searched for in SubClass at runtime, although they'll be searched in SuperClass at compile-time. It turns out, as I now think I understand, that whatever method is called on sc will be searched for in SuperClass at both compile-time and run-time, UNLESS SubClass has provided a "better" version of the method. Then, even at compile-time, the compiler will know the method to invoke is the SubClass version.

+6  A: 

A method with a String[] or String... parameter and a method with a String parameter do not share the same signature. A string array is an entirely separate type, so it's a standard overload and polymorphism is not taking place. The compiler sees it's an instance of type "Alpha" and invokes the foo method found there. The foo method in Beta is not called because it is not actually an override of the Alpha version.

(This is where the @Override annotation comes in handy. If you tried to use it on the Beta version of foo, you'd get a compiler error.)

Kirk Woll
+4  A: 

Method overloading is realized at compile-time, method overriding - at runtime.

In your case, the foo in Beta does not override foo in Alpha. It overloads it with different arguments (You can prove this by adding the @Override annotation, which is a best practice for detecting such not-so-obvious potential problems).

Another sneaky thing here is that you can't invoke Alpha#foo(..) from a reference of Beta - i.e. b.foo("test") will always invoke the non-varargs method. As of why this happens, see this question

Bozho
+2  A: 

Since a and b "foo()" methods does not have the same signature, b "foo()" method doesn't override a "foo()" method.

For that reason, when you call "a.foo()", Alpha.foo().

To verify that, you can try to put an "@Override" annotation on "b.foo()" method. This will result in a compilation error (since "b.foo()" overrides nothing).

Benoit Courtine
+2  A: 

When you say Super a = new Sub(); and do a a.methodCall(); following rule applies..

See if sub class has a method that overrides method in super class and calls it.

But here method in sub class does not overrides but overloads the method in super hence an implementation of superclass is called. When you make arguments to the two methods same. Then overriding principle applies.

sushil bharwani
A: 

Overriding comes at run time, here in your case you are not overriding foo method as parameters of methods in super class and sub class are different.A method with a String[] or String... parameter and a method with a String parameter are not same.

giri