返回泛型类型的交集

Ben*_*ler 4 java generics java-7

我想让一个函数返回一个保证实现两个接口的对象。在编译时不一定知道确切的对象。我的代码看起来像:

class HelloWorld {

  public interface A {}
  public interface B {}

  public static class C implements A, B {}
  public static class D implements A, B {}

  public static <T extends A & B> void g(T t) {}

  public static <T extends A & B> T f(boolean b) {
    if (b)
      return new C(); // Doesn't compile
    return new D(); // Doesn't compile
  }

  public static void main(String []args){
    g(f(true));
    g(f(false));
    <what_should_I_write_here> x = f(<user_inputted_boolean>); 
  }
}
Run Code Online (Sandbox Code Playgroud)

尝试编译时出现以下错误:

HelloWorld.java:13: 错误:类型不兼容:C 无法转换为 T
return new C();
^
其中 T 是类型变量:
T extends A,B 在方法 f(boolean)
HelloWorld.java:14 中声明:错误:不兼容的类型:D 无法转换为 T
return new D();
^
其中 T 是类型变量:
T extends A,B 在方法 f(boolean) 中声明

这不起作用,因为您不能从函数返回两种不同的类型,并且CD是不同的类型。

有没有办法让上面的代码编译?

Hol*_*ger 5

您对类型变量有根本的误解。当你声明一个方法时

public static <T extends A & B> T f(boolean b) { … }
Run Code Online (Sandbox Code Playgroud)

您声明了一个类型变量 T调用者可以为其分配实际类型(或调用者上下文的类型变量)。例如,调用者可以执行以下操作:

class SomethingCompletelyUnknownToF implements A,B {}

SomethingCompletelyUnknownToF var = f(trueOrFalse);
Run Code Online (Sandbox Code Playgroud)

编译器会接受,因为调用者SomethingCompletelyUnknownToF使用的类型满足类型必须实现的约束or 。当然,这将在运行时失败,因为既不能也不能分配给. 事实上,它不可能满足返回它甚至不知道的特定类型的期望。TfABCDSomethingCompletelyUnknownToFf

总而言之,类型变量不是方法可以分配类型的变量,类型变量是调用者选择的类型的占位符。

所以方法签名

public static <T extends A & B> void g(T t) { … }
Run Code Online (Sandbox Code Playgroud)

更有意义的是,无论调用者选择的实际类型如何T,它将满足方法的实现期望,A并且B在作为参数传递时。当然,g不能指望它是,D或者C,因为它可能是一个完全未知的类型,实现了AB

也就是说,在 Java 中没有办法表示返回类型扩展了两种类型(除了声明扩展这两种类型的具体类型)。在的情况下RandomAccess,无论如何都不需要打扰,因为它没有任何后果。请注意,JRE 类也永远不会声明返回的何时List保证实现此标记接口。这是通过从不期望它作为参数类型来适应的。同样,Serializable永远不会在任何地方声明为返回或参数类型。