Reputation: 2894
I have a (non abstract) generic base class A<L,M>
, an abstract generic sub class B<K, L, M> extends A<L,M>
and a (non abstract) class C extends B<Integer, Integer, Void>
:
public class A<L,M> { }
public abstract class B<K, L, M> extends A<L,M> { }
public class C extends B<Integer, Integer, Void> { }
I have a utils class that has a few methods, two are relevant here:
public static <K, L, M> void doSomething(B<K, L, M> b) {...}
public static <L, M> void doSomething(A<L, M> a) {...}
To be clear, both methods have the same name.
If I call doSomething(c);
(where C c
) it goes as expected to the 1st method.
My issue is with the following code (at another class that uses the utils):
private void doSomethingMoreComplex(A a) { // a is actually C
Utils.doSomething(a);
}
So here a
is actually C
but it goes to the second method, I am not sure if I made a mistake in the code or this is actually the expected behavior.
Upvotes: 1
Views: 125
Reputation: 311948
This is the expected behavior. The runtime type of a
is inconsequential, as this method resolution is done in compile time. Since doSomething(B)
cannot be applied to an argument of type A
, the method is resolved to doSomething(A)
.
You could handle this yourself by explicitly downcasting a
:
private void doSomethingMoreComplex(A a) { // a is actually C
if (a instanceof B) {
Utils.doSomething((B) a);
} else {
Utils.doSomething(a);
}
}
... but, well, in a word - yuck.
The more idiomatic way to address this would be to have doSomething
as a method of A
and override (not overload) it in B
.
Upvotes: 3
Reputation: 140494
or this is actually the expected behavior.
Yes, it's the expected behavior.
The compiler chooses which method is run, and it doesn't know that it is a B
(because you've said it's an A
). So it doesn't know if the first overload is safe to invoke, but it knows the second overload is.
Upvotes: 3