返回泛型类型的交集 [英] Return intersection of generic types

查看:91
本文介绍了返回泛型类型的交集的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

  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扩展A& B个void g(T t){}

public static< T extends A& B个T f(boolean b){
if(b)
return new C(); //不编译
返回新的D(); //不会编译
}

public static void main(String [] args){
g(f(true));
g(f(false));
> x = f(< user_inputted_boolean>);


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


HelloWorld.java:13:错误:不兼容的类型:C无法转换为T
返回新的C() ;

^

其中T是一个类型变量:

T扩展A,B在f(boolean)方法中声明

HelloWorld.java:14:错误:不兼容的类型:D无法转换为T

返回新的D();

^

其中T是类型-variable:

T扩展A,B在f(boolean)方法中声明

这不起作用因为你不能从一个函数返回两个不同的类型,并且 C D 是不同的类型。



有没有什么办法可以让上面的代码编译?

解决方案

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

  public static< T extends A& B个你声明一个类型的变量  T   caller 可以为其分配实际类型(或调用者上下文的类型变量)。例如,调用者可以执行以下操作:

  class SomethingCompletelyUnknownToF implements A,B {} 

SomethingCompletelyUnknownToF var = f(trueOrFalse);

编译器会接受,因为类型 SomethingCompletelyUnknownToF f 的调用者用于 T 的c>实现了约束,即类型必须实现 A B 。当然,这会在运行时失败,因为 C D 都可以分配给 SomethingCompletelyUnknownToF 。事实上, f 不可能满足这种期望返回它甚至不知道的特定类型。



总之,一个类型变量不是一个变量,该方法可以指定一个类型,类型变量是调用者选择的类型的一个占位符。



所以方法签名

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

更有意义,因为调用者选择的实际类型 T ,它将满足方法对实现 A B 当作为参数传递时。当然, g 不能指望它是 D C ,因为它可能是一个完全未知的类型,它执行 A B



也就是说,在Java中没有办法表示返回类型扩展了两种类型(除了声明扩展两种类型的具体类型)。在 RandomAccess 的情况下,无需担心,因为它没有任何影响。请注意,当返回的 List 保证实现这个标记接口时,JRE类也从不声明。永远不要期望它作为参数类型。同样, Serializable 永远不会被声明为返回或参数类型。


I would like to have a function return an object that is guaranteed to implement two interfaces. The exact object is not necessarily known at compilation time. My code looks something like:

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>); 
  }
}

When trying to compile I get the following error:

HelloWorld.java:13: error: incompatible types: C cannot be converted to T
return new C();
^
where T is a type-variable:
T extends A,B declared in method f(boolean)
HelloWorld.java:14: error: incompatible types: D cannot be converted to T
return new D();
^
where T is a type-variable:
T extends A,B declared in method f(boolean)

This doesn't work because you can't return two different types from a function and C and D are different types.

Is there any way to get the above code to compile?

解决方案

You have a fundamental misunderstanding regarding type variables. When you declare a method like

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

you declaring a type variable T to which the caller may assign an actual type (or a type variable of the caller’s context). E.g., the caller may do the following:

class SomethingCompletelyUnknownToF implements A,B {}

SomethingCompletelyUnknownToF var = f(trueOrFalse);

which the compiler will accept, because the type SomethingCompletelyUnknownToF used for T by the caller of f fulfills the constraint that the type must implement A or B. Of course, this will fail at runtime, because neither C nor D are assignable to SomethingCompletelyUnknownToF. In fact, it is impossible for f to fulfill this expectation of returning a specific type that it doesn’t even know.

To summarize, a type variable is not a variable that the method may assign a type, a type variable is a placeholder for a type chosen by the caller.

So the method signature

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

makes more sense as whatever actual type the caller chooses for T, it will fulfill the method’s expectation of implementing A and B when being passed as parameter. Of course, g can not expect it to be either, D or C, as it might be a completely unknown type implementing A and B.

That said, there is no way in Java, to express that a return type extends two types (other than declaring a concrete type extending both). In case of RandomAccess, there is no need to bother anyway, as it has no consequences. Note that the JRE classes also never declare when a returned List is guaranteed to implement this marker interface. This is accommodated by never expecting it as parameter type either. Similarly, Serializable is never declared as return or parameter type anywhere.

这篇关于返回泛型类型的交集的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆