Java泛型 - 为什么允许“扩展T”而不是“实现T”?

时间:2009-06-10 15:42:34

标签: java generics syntax design-choices

我想知道Java中是否有特殊原因使用“extends”而不是“implements”来定义类型参数的边界。

示例:

public interface C {}
public class A<B implements C>{} 

被禁止但

public class A<B extends C>{} 

是对的。这是什么原因?

8 个答案:

答案 0 :(得分:320)

在类“实现”或“扩展”之间,通用约束语言没有语义差异。约束的可能性是'extends'和'super' - 也就是说,这个类是否可以赋值给另一个(扩展),或者这个类可以从那个(超级)分配。

答案 1 :(得分:56)

答案在here

  

要声明有界类型参数,请列出类型参数的名称,然后是extends关键字,后跟上限 [...]。请注意,在此上下文中,extends在一般意义上用于表示extends(如在类中)或implements(如在接口中)。

所以,你有它,它有点令人困惑,而甲骨文知道它。

答案 2 :(得分:17)

可能因为双方(B和C)只有类型是相关的,而不是实现。 在你的例子中

public class A<B extends C>{}

B也可以是一个界面。 “extends”用于定义子接口和子类。

interface IntfSub extends IntfSuper {}
class ClzSub extends ClzSuper {}

我通常认为'Sub extends Super'为' Sub 就像 Super ,但有其他功能','Clz实现Intf'为' Clz Intf '的实现。在您的示例中,这将匹配: B 类似于 C ,但具有其他功能。这些功能与此相关,而不是实现。

答案 3 :(得分:7)

基类型可能是通用参数,因此实际类型可能是类的接口。考虑:

class MyGen<T, U extends T> {

同样从客户端代码的角度来看,接口几乎与类无法区分,而对于子类型则很重要。

答案 4 :(得分:7)

这是一个更为复杂的例子,其中允许扩展,也可能是你想要的:

public class A<T1 extends Comparable<T1>>

答案 5 :(得分:5)

使用哪种术语是任意的。它可能是两种方式。也许语言设计师认为&#34;扩展&#34;作为最基本的术语,&#34;实现&#34;作为接口的特例。

但我认为implements会更有意义。我认为更多地传达参数类型不必处于继承关系中,它们可以处于任何类型的子类型关系中。

Java词汇表表达similar view

答案 6 :(得分:1)

我们习惯

class ClassTypeA implements InterfaceTypeA {}
class ClassTypeB extends ClassTypeA {}

与这些规则的任何微小差异都会使我们感到困惑。

类型绑定的语法定义为

TypeBound:
    extends TypeVariable 
    extends ClassOrInterfaceType {AdditionalBound}

JLS 12 > 4.4. Type Variables > TypeBound

如果要更改它,我们肯定会添加implements大小写

TypeBound:
    extends TypeVariable 
    extends ClassType {AdditionalBound}
    implements InterfaceType {AdditionalBound}

并以两个相同处理的子句结束

ClassOrInterfaceType:
    ClassType 
    InterfaceType

JLS 12 > 4.3. Reference Types and Values > ClassOrInterfaceType

除了我们还需要注意implements,这会使事情进一步复杂化。

我认为,这是使用extends ClassOrInterfaceType而不是extends ClassTypeimplements InterfaceType的主要原因-在复杂的概念中使事情保持简单。问题在于我们没有一个合适的词来涵盖extendsimplements,而且我们绝对不想引入一个词。

<T is ClassTypeA>
<T is InterfaceTypeA>

尽管extends在与接口一起使用时会带来一些混乱,但这是一个广义的术语,可以用来描述这两种情况。尝试使您的思想适应扩展类型的概念(而不是扩展类,而不是实现接口)。您可以通过另一种类型来限制类型参数,实际上该类型是什么都没有关系。唯一重要的是它的上限和它的超类型

答案 7 :(得分:-1)

实际上,当在接口上使用泛型时,关键字也会扩展。这是代码示例:

有2个类实现了Greeting接口:

interface Greeting {
    void sayHello();
}

class Dog implements Greeting {
    @Override
    public void sayHello() {
        System.out.println("Greeting from Dog: Hello ");
    }
}

class Cat implements Greeting {
    @Override
    public void sayHello() {
        System.out.println("Greeting from Cat: Hello ");
    }
}

测试代码:

@Test
public void testGeneric() {
    Collection<? extends Greeting> animals;

    List<Dog> dogs = Arrays.asList(new Dog(), new Dog(), new Dog());
    List<Cat> cats = Arrays.asList(new Cat(), new Cat(), new Cat());

    animals = dogs;
    for(Greeting g: animals) g.sayHello();

    animals = cats;
    for(Greeting g: animals) g.sayHello();
}