【问题标题】:Can you specify a generic type that subclasses another generic type _and_ a concrete interface?你能指定一个泛型类型来继承另一个泛型类型_and_一个具体接口吗?
【发布时间】:2013-11-27 20:32:43
【问题描述】:

我有一系列领域模型,每个模型都有一个扩展它的子类并且实现了一个特定的接口,就像这样(Cloneable 不是有问题的接口,它是用于示例目的仅):

class A{}
class B extends A implements Cloneable{}

class C{}
class D extends C implements Cloneable{}

我想创建一个通用类型签名来强制执行这种配对,我已经尝试过 FAILS

<T1,T2 extends T1 & Cloneable> void f ( T1 t1, T2 t2 ){}

但我在 IntelliJ IDE "Type parameter cannot be followed by other bounds" 中收到消息;如果我将顺序切换到以下位置,它仍然失败

<T1,T2 extends Cloneable & T1> void f ( T1 t1, T2 t2 ){}

我收到消息"Interface expected here."

令人困惑的是,这两个签名WORK

<T extends A & Cloneable> void f( A a, T t ){}
<T1,T2 extends T1> void f ( T1 t1, T2 t2 ){}

这只是 Java 泛型类型系统的一个奇怪限制,我不能让泛型类​​(即T2)同时扩展另一个泛型类(即T1和 一个具体的接口(例如Cloneable)?

tl;dr: 那么,为什么&lt;T1,T2 extends Cloneable &amp; T1&gt; void f ( T1 t1, T2 t2 ){} 不编译:这是 Java 泛型语法的限制还是我使用了错误的语法?

【问题讨论】:

  • 是的,Java 类型的另一个奇怪而不幸的限制是,如果涉及类型变量,则不能进行交集类型约束。给出的理由显然是为了避免“某些有问题的情况”。
  • @PaulBellora 虽然答案可能相同,但我的问题与两个界面之一不同。
  • @JudgeMental 似乎编译时间可以检查,所以我真的会对所涉及的实际细节感到好奇。
  • @ArtB 查看对该问题的编辑(有赏金)和我的回答。我知道这有点令人困惑。第二个链接的帖子更明显是重复的。

标签: java generics


【解决方案1】:

答案在JLS 4.4

TypeParameter:
    TypeVariable TypeBoundopt

TypeBound:
    extends TypeVariable
    extends ClassOrInterfaceType AdditionalBoundListopt

AdditionalBoundList:
    AdditionalBound AdditionalBoundList
    AdditionalBound

AdditionalBound:
    & InterfaceType

&amp; Cloneable 是 AdditionalBound,只能在 AdditionalBoundList 中使用。 AdditionalBoundList 只能在 ClassOrInterfaceType 之后使用。而T1 是一个 TypeVariable,而不是 ClassOrInterfaceType。

所以,是的,这是 Java 泛型语法的限制。

【讨论】:

    【解决方案2】:

    &lt;T1,T2 extends Cloneable &amp; T1&gt; void f ( T1 t1, T2 t2 ){}

    我收到消息“此处需要接口。”

    来自jls 4.4. Type Variables:

    每个声明为类型参数的类型变量都有一个界限。如果不 bound 是为类型变量声明的,假定是 Object。如果有界 被声明,它包括:

    - a single type variable T, or
    
    - a class or interface type T possibly followed by interface types `I1 & ... & In`.
    

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

    因此,对于表达式&lt;T extends C &amp; I&gt; void test(T t)I 应该是一个接口。

    【讨论】:

    • I 在原问题中是Cloneable,这是一个接口。问题出在C,它必须是类或接口(但不是类型变量)。
    • @yshavit,请看我答案的开头,我在其中引用了他的一个问题。他实际上有两个问题。我用&lt; 粘贴了带有&gt; 代码的问题,它隐藏了帖子中的&lt;T1,T2 extends Cloneable &amp; T1&gt; 部分。 :)
    • 别这样,我不能正确粘贴是我的错:)
    猜你喜欢
    • 2014-12-19
    • 2023-03-06
    • 2018-07-23
    • 1970-01-01
    • 2020-12-05
    • 1970-01-01
    • 2014-08-02
    • 2021-12-25
    • 1970-01-01
    相关资源
    最近更新 更多