我有一个(非抽象的)通用基数class A<L,M>
,一个抽象的通用子类class B<K, L, M> extends A<L,M>
和一个(非抽象的)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> { }
我有一个utils类,其中有一些方法,这里有两个相关的方法:
public static <K, L, M> void doSomething(B<K, L, M> b) {...}
public static <L, M> void doSomething(A<L, M> a) {...}
要清楚,这两种方法的名称相同。
如果我调用doSomething(c);
(在C c
处),则按预期方法进行第一种方法。
我的问题是以下代码(在使用utils的另一个类中):
private void doSomethingMoreComplex(A a) { // a is actually C
Utils.doSomething(a);
}
因此,这里的a
实际上是C
,但是它涉及第二种方法,我不确定是否在代码中犯了错误,或者这实际上是预期的行为。
答案 0 :(得分:3)
或者这实际上是预期的行为。
是的,这是预期的行为。
编译器选择运行哪个方法,并且它不知道它是B
(因为您已经说过它是A
)。因此,它不知道第一个重载是否可以安全调用,但它知道第二个重载是安全的。
答案 1 :(得分:3)
这是预期的行为。 a
的运行时类型无关紧要,因为此方法解析是在编译时完成的。由于doSomething(B)
无法应用于类型为A
的参数,因此该方法将解析为doSomething(A)
。
您可以通过显式下传a
来自己处理:
private void doSomethingMoreComplex(A a) { // a is actually C
if (a instanceof B) {
Utils.doSomething((B) a);
} else {
Utils.doSomething(a);
}
}
...但是,总而言之-。
解决此问题的更惯用的方法是将doSomething
作为A
的一种方法,并对其进行覆盖(不超载) B
。