334

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

例子:

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

被禁止但

public class A<B extends C>{} 

是正确的。这是什么原因?

4

8 回答 8

340

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

于 2009-06-10T15:45:51.503 回答
95

答案在这里 :

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

所以你有它,它有点令人困惑,Oracle 知道这一点。

于 2016-11-03T02:01:44.363 回答
19

可能是因为对于双方(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”是“ ClzIntf的实现”。在您的示例中,这将匹配:B类似于C,但具有附加功能。能力在这里是相关的,而不是实现。

于 2009-06-10T16:08:15.233 回答
7

可能基类型是泛型参数,所以实际类型可能是类的接口。考虑:

class MyGen<T, U extends T> {

同样从客户端代码的角度来看,接口与类几乎没有区别,而对于子类型来说它很重要。

于 2009-06-10T15:48:50.763 回答
7

这是一个更复杂的示例,说明允许扩展的位置以及您可能想要的内容:

public class A<T1 extends Comparable<T1>>

于 2012-07-31T13:48:57.567 回答
5

使用哪个术语有点随意。它可能是任何一种方式。也许语言设计者认为“扩展”是最基本的术语,而“实现”是接口的特例。

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

Java Glossary 表达了类似的观点

于 2016-01-22T09:02:43.257 回答
4

我们习惯了

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

任何与这些规则的轻微偏差都会使我们大为困惑。

类型绑定的语法定义为

TypeBound:
    extends TypeVariable 
    extends ClassOrInterfaceType {AdditionalBound}

( JLS 12 > 4.4. 类型变量 >TypeBound )

如果我们要更改它,我们肯定会添加implements案例

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

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

ClassOrInterfaceType:
    ClassType 
    InterfaceType

( JLS 12 > 4.3. 引用类型和值 >ClassOrInterfaceType )

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

extends ClassOrInterfaceType我相信这是使用而不是extends ClassType和的主要原因implements InterfaceType- 在复杂的概念中保持简单。问题是我们没有合适的词来涵盖两者extendsimplements而且我们绝对不想介绍一个。

<T is ClassTypeA>
<T is InterfaceTypeA>

尽管extends与接口一起使用时会带来一些混乱,但它是一个更广泛的术语,可以用来描述这两种情况。尝试将您的思想调整到扩展类型的概念(不扩展类,不实现接口)。您通过另一种类型限制类型参数,该类型实际上是什么并不重要。重要的是它是它的上限和它的超类型

于 2019-05-25T11:53:57.203 回答
-1

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

有 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();
}
于 2020-01-07T14:57:59.970 回答