返回泛型类型

时间:2016-06-15 12:44:07

标签: 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>); 
  }
}

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

  

HelloWorld.java:13:错误:不兼容的类型:C无法转换为T
          返回新的C();
                 ^
    其中T是一个类型变量:
      T扩展A,B在方法f(布尔值)中声明   HelloWorld.java:14:错误:不兼容的类型:D无法转换为T
        返回新的D();
               ^
    其中T是一个类型变量:
      T扩展了方法f(布尔值)

中声明的A,B

这不起作用,因为您无法从函数中返回两种不同的类型,CD是不同的类型。

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

2 个答案:

答案 0 :(得分:4)

你对类型变量有一个基本的误解。当您声明类似

的方法时
public static <T extends A & B> T f(boolean b) { … }

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

class SomethingCompletelyUnknownToF implements A,B {}

SomethingCompletelyUnknownToF var = f(trueOrFalse);
编译器将接受的

,因为SomethingCompletelyUnknownToF调用者对T使用的类型f满足类型必须实现的约束A或{{1 }}。当然,这会在运行时失败,因为BC都不能分配给D。事实上,SomethingCompletelyUnknownToF不可能满足这种期望,即返回它甚至不知道的特定类型。

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

所以方法签名

f

与调用者为public static <T extends A & B> void g(T t) { … } 选择的实际类型更有意义,它将满足方法在作为参数传递时实现TA的期望。当然,B不能指望它是gD,因为它可能是实现CA的完全未知的类型。< / p>

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

答案 1 :(得分:1)

我同意霍尔格在their answer中所说的一切。但是我想补充一点,因为棘手的类型非常有趣。

我相信你喜欢做的事情是让交集返回类型为f,如下所示:

public static A & B f(boolean b)

然后f会返回一个同时实现AB的对象。这将使方法类型的返回语句检查,您可以将其返回值分配给AB变量。

但当然这是不允许的,Java中的交集类型只允许在类型变量上使用。

你可以试试这个:

public static Optional<? extends A & B> f(boolean b)

这里的交集类型没问题,因为它实例化了Optional的类型参数。但是这是不允许的,因为通配符只能有一个绑定,&不能使用。

Ceylon 是一种非常有趣的编程语言,它支持一流的交集和联合类型。你可以在锡兰写上面的例子。

检查一下,真的有趣!