未能为从泛型方法调用的方法选择正确的重载

Failure to choose a right overload for method called from a generic method

我有以下代码:

class A{}
class B{}
class StuffDoer {
  public void doStuff(A a) { System.out.println("A"); }
  public void doStuff(B b) { System.out.println("B"); }
  public void doStuff(Object o) { System.out.println("Object"); }
}

class Test {
  private final StuffDoer stuffDoer;

  public <T> void foo(T t) {
    stuffDoer.doStuff(t)
  }
}

执行后

Test test = new Test();
A a = new A();
B b = new B();
test.foo(a);
test.foo(b);

两次打印“Object”,而不是之后预期的“A”和“B”。

如果我显式传递一个 Class 对象也不起作用

class Test {
  private final StuffDoer stuffDoer;

  public <T> void foo(T t) { //doesnt work
    stuffDoer.doStuff(t.getClass().cast(t))
  }

  public <T> void foo(T t, Class<T> tClass) { //doesnt work either
    stuffDoer.doStuff(tClass.cast(t))
  }

}

只有当我像这样在 foo 方法中将它们显式转换为适当的对象时它才有效

class Test {
  private final StuffDoer stuffDoer;

  public <T> void foo(T t) {
    if ( t instanceof A ) 
      stuffDoer.doStuff((A) t) // Prints "A"
    else if ( t instance of B ) 
      stuffDoer.doStuff((B) t) // Prints "B"
    else
      stuffDoer.doStuff(t) // Prints "Object"
  }
}

这是为什么?我怎样才能从泛型类型获得正确的方法重载?在 Java 中甚至可能吗?

在 Java 中,只有 method receiver 是在运行时动态选择的,而方法的签名是在编译时使用提供的参数类型确定的,因此 doStuff(Object o)方法被选为唯一可能的方法(将其注释掉会导致 compile-time 错误)。

没有太多选项可以按照您想要的方式“模拟”多重分派:

  • 你已经提到的instanceof

  • 一个Visitor/Strategy模式

  • 通过反射或MethodHandle

    的动态方法查找
  • 模式匹配(自 Java 17):

    public <T> void foo(T t) {
        switch (t) {
            case A a  -> stuffDoer.doStuff(a);
            case B b  -> stuffDoer.doStuff(b);
            case null -> System.out.println("OOPS :(");
            default   -> stuffDoer.doStuff(t);
        }
    }