Return intersection of generic types

送分小仙女□ 提交于 2019-12-12 14:25:50

问题


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?


回答1:


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.




回答2:


I agree with everything Holger says in their answer. But I'd like to add one thing, just because tricky types are so much fun.

I believe what you'd like to do is to have a intersection return type of f, like this:

public static A & B f(boolean b)

Then f would return some object which implements both A and B. This would make the return-statements of the method type check and you could assign its return value to either A or B variables.

But of course this is not allowed, intersection types in Java are only allowed on type variables.

You could try this:

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

Here a intersection type is okay because it instantiates the type parameter of Optional. But this is not allowed anyway since wildcards can only have one bound, & can not be used.


Ceylon is a very interesting programming language which has support for first-class intersection and union types. You could write the above examples in Ceylon.

Check it out, its really interesting!



来源:https://stackoverflow.com/questions/37835850/return-intersection-of-generic-types

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!