我最近刚刚开始摆弄 Java 中的泛型,并且遇到了一些奇怪的行为。这是简化版本,但我有一个基类,该基类由传递到通用函数的多个类扩展。在这个函数中,我调用了一个具有多个版本的方法,这些版本采用不同的基类或派生类作为参数。
如果我有以下内容:
public class A{};
public class B extends A{};
public class C extends A{};
public class Runner
{
public static void Run( ClassA a ){Do Something};
public static void Run( ClassB b ){Do Something};
public static void Run( ClassC c ){Do Something};
}
void SomeRandomCall<B extends ClassA>( B b )
{
Runner.Run( b );
}
SomeRandomCall<ClassB>( new ClassB() );
我在调试中发现 Runner.Run
正在调用 Run( ClassA a )
而不是 Run( ClassB b )
函数。给定这两个函数,既然提供了类型特定的函数,难道不应该调用 Run( ClassB b )
吗?
如果不是这种情况,我如何能够拥有一个通用函数来调用能够调用具有采用基类和派生类的签名的函数?
最佳答案
由于您的缩写对我来说有点令人困惑,因此我制作了一个可运行的小示例。我假设您的 SomeRandomCall
中的 B
是泛型类型,而不是类 B。
这里是:
public class Main {
public static class A{};
public static class B extends A{};
public static class C extends A{};
public static class Runner{
public static void Run( A a ){System.out.println("A");};
public static void Run( B b ){System.out.println("B");};
public static void Run( C c ){System.out.println("C");};
}
static <T extends A> void SomeRandomCall( T x ){
Runner.Run( x );
}
public static void main(String[] args) {
B b = new B();
new Runner().Run( b );
}
}
输出为:B。
这正是您所期望的,这很好。在编译时,Java 编译器会选择方法的候选对象,即 Run( A a )
和 Run( B b )
。运行时,参数的类型为B,因此打印B。
但是,请注意以下示例:
public static void main(String[] args) {
A ab = new B();
new Runner().Run( ab );
}
现在会发生什么?现在输出是 A。原因是,在编译时,ab
的类型为 A
,因此我们只有一个候选方法可以执行:Run(一个)
。运行时 ab 的实际类型不再重要,因为我们只有一个可以执行的候选类型。无论 ab
是 A
、B
还是 C
,输出都是 A .
关于Java 多态泛型调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22116010/