Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How was one method chosen over another in this code?

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.

like image 334
Bad Request Avatar asked Sep 25 '10 18:09

Bad Request


People also ask

How do you replace a word in VS Code?

You can use the Find control in code or text windows, such as Output windows and Find Results windows, by selecting Edit > Find and Replace or pressing Ctrl+F.


4 Answers

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.)

like image 170
Kirk Woll Avatar answered Oct 20 '22 04:10

Kirk Woll


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

like image 25
Bozho Avatar answered Oct 20 '22 03:10

Bozho


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).

like image 2
Benoit Courtine Avatar answered Oct 20 '22 03:10

Benoit Courtine


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.

like image 2
sushil bharwani Avatar answered Oct 20 '22 02:10

sushil bharwani