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:bar
which 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.
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.
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.)
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
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).
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With