带有接口类和类型变量的Java交集类型的限制

时间:2017-10-24 13:48:36

标签: java types jls

今天我尝试用一​​个使用交集类型的泛型方法编写一个类,并根据相交类型对不同的错误消息感到困惑。我们假设我们有interfaceclass并在通用接口中定义泛型方法:

class ClassType {
}

interface InterfaceType {
}

interface I<T> {
    public <X extends InterfaceType & InterfaceType> void foo();

    public <X extends ClassType & ClassType> void foo1();

    public <X extends ClassType & InterfaceType> void foo2();

    public <X extends InterfaceType & ClassType> void foo3();

    public <X extends T & ClassType> void foo4();

    public <X extends ClassType & T> void foo5();

    public <X extends InterfaceType & T> void foo6();

    public <X extends T & InterfaceType> void foo7();
}

编译这会产生除public <X extends ClassType & InterfaceType> void foo2();之外的所有方法的错误。

Main.java:8: error: repeated interface
    public <X extends InterfaceType & InterfaceType> void foo();
                                      ^
Main.java:10: error: interface expected here
    public <X extends ClassType & ClassType> void foo1();
                                  ^
Main.java:14: error: interface expected here
    public <X extends InterfaceType & ClassType> void foo3();
                                      ^
Main.java:16: error: a type variable may not be followed by other bounds
    public <X extends T & ClassType> void foo4();
                          ^
Main.java:18: error: unexpected type
    public <X extends ClassType & T> void foo5();
                                  ^
  required: class
  found:    type parameter T
  where T is a type-variable:
    T extends Object declared in interface I
Main.java:20: error: unexpected type
    public <X extends InterfaceType & T> void foo6();
                                      ^
  required: class
  found:    type parameter T
  where T is a type-variable:
    T extends Object declared in interface I
Main.java:22: error: a type variable may not be followed by other bounds
    public <X extends T & InterfaceType> void foo7();
                          ^
7 errors

由于交叉点应该是对称的,我很惊讶foo2被接受但foo3被拒绝。为什么接受这一案件?

我也想知道为什么在交集类型方面为什么接口,类和类型参数之间存在区别。我可以看到在交集类型中不允许多个类的原因,但接受ClassType & InterfaceType但不接受InterfaceType & ClassType的当前状态似乎有点奇怪。交叉点A & A也被禁止,但这在语义上与A相同,所以我不明白这个原因。

我也很好奇为什么交叉路口不允许使用类型变量。最坏的情况是两个或更多类的交集,但只是一个无人居住的类型,所以底部类型。

2 个答案:

答案 0 :(得分:2)

您只能拥有1个类但具有多个接口。如果你有一个类,它必须是指定的第一个类。如果您遵循此规则,则不应该收到任何编译错误。

请参阅https://docs.oracle.com/javase/tutorial/java/generics/bounded.html

答案 1 :(得分:0)

这在 4.4 The Java Language specification的类型变量

中进行了说明
  

类型变量是在类中用作类型的不合格标识符,   接口,方法和构造函数主体。

     

类型变量是   由泛型类的类型参数的声明引入,   接口,方法或构造函数(第8.1.2节,第9.1.2节,第8.4.4节,第8.8.4节)。

TypeParameter:
    {TypeParameterModifier} TypeIdentifier [TypeBound]

TypeParameterModifier:
   Annotation

TypeBound:
    extends TypeVariable
    extends ClassOrInterfaceType {AdditionalBound}

AdditionalBound:
    & InterfaceType
     

在6.3节中指定了声明为type参数的类型变量的范围。

     

每个声明为类型的类型变量   参数有界。如果没有为类型变量声明边界,   假定对象。如果声明了界限,则界限由以下任意一项组成:

     
      
  • 单个类型变量T
  •   
  • 类或接口类型T后面可能跟着接口类型I1 & ... & In
  •   
     

这是一个编译时错误   如果任何类型I1 ... In是类类型或类型变量。

     

  边界的所有组成类型的擦除(第4.6节)必须成对进行   不同,或者发生编译时错误。

     

类型变量不得位于   同时是两个不同接口类型的子类型   相同通用接口的参数化或编译时   错误发生。

     

边界中的类型顺序仅在   类型变量的擦除是由   它的边界,并且类类型或类型变量只能出现在   第一位置。

     

边界为X的类型变量T & I1 & ... & In的成员是交集类型(§4.9)T & I1 & ... & In的成员,出现在声明类型变量的位置。