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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/976441/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 21:47:43  来源:igfitidea点击:

Java generics - why is "extends T" allowed but not "implements T"?

javagenericssyntaxdesign-choices

提问by user120623

I wonder if there is a special reason in Java for using always "extends" rather than "implements" for defining bounds of typeparameters.

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

Example:

例子:

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

is prohibited but

被禁止但

public class A<B extends C>{} 

is correct. What is the reason for that?

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

回答by Tetsujin no Oni

There is no semantic difference in the generic constraint language between whether a class 'implements' or 'extends'. The constraint possibilities are 'extends' and 'super' - that is, is this class to operate with assignable to that other one (extends), or is this class assignable from that one (super).

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

回答by Tom Hawtin - tackline

It may be that the base type is a generic parameter, so the actual type may be an interface of a class. Consider:

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

class MyGen<T, U extends T> {

Also from client code perspective interfaces are almost indistinguishable from classes, whereas for subtype it is important.

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

回答by beetstra

Probably because for both sides (B and C) only the type is relevant, not the implementation. In your example

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

public class A<B extends C>{}

B can be an interface as well. "extends" is used to define sub-interfaces as well as sub-classes.

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

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

I usually think of 'Sub extends Super' as 'Subis like Super, but with additional capabilities', and 'Clz implements Intf' as 'Clzis a realization of Intf'. In your example, this would match: Bis like C, but with additional capabilities. The capabilities are relevant here, not the realization.

我通常认为“Sub extends Super”是“ Sub类似于Super,但具有附加功能”,而“Clz 实现 Intf”则是“ ClzIntf的实现”。在您的示例中,这将匹配:B类似于C,但具有附加功能。能力在这里是相关的,而不是实现。

回答by ntg

Here is a more involved example of where extends is allowed and possibly what you want:

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

public class A<T1 extends Comparable<T1>>

public class A<T1 extends Comparable<T1>>

回答by Lii

It's sort of arbitrary which of the terms to use. It could have been either way. Perhaps the language designers thought of "extends" as the most fundamental term, and "implements" as the special case for interfaces.

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

But I think implementswould make slightly more sense. I think that communicates more that the parameter types don't have to be in an inheritance relationship, they can be in anykind of subtype relationship.

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

The Java Glossary expresses a similar view.

Java 词汇表表达了类似的观点

回答by MikaelF

The answer is in here?:

答案在这里?:

To declare a bounded type parameter, list the type parameter's name, followed by the extendskeyword, followed by its upper bound[…]. Note that, in this context, extends is used in a general sense to mean either extends(as in classes) or implements(as in interfaces).

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

So there you have it, it's a bit confusing, and Oracle knows it.

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

回答by Andrew Tobilko

We are used to

我们习惯了

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

and any slight deviation from these rules greatly confuses us.

任何对这些规则的轻微偏离都会让我们感到非常困惑。

The syntax of a type bound is defined as

类型绑定的语法定义为

TypeBound:
    extends TypeVariable 
    extends ClassOrInterfaceType {AdditionalBound}

(JLS 12 > 4.4. Type Variables > TypeBound)

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

If we were to change it, we would surely add the implementscase

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

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

and end up with two identically processed clauses

并最终得到两个相同处理的子句

ClassOrInterfaceType:
    ClassType 
    InterfaceType

(JLS 12 > 4.3. Reference Types and Values > ClassOrInterfaceType)

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

except we would also need to take care of implements, which would complicate things further.

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

I believe it's the main reason why extends ClassOrInterfaceTypeis used instead of extends ClassTypeand implements InterfaceType- to keep things simple within the complicated concept. The problem is we don't have the right word to cover both extendsand implementsand we definitely don't want to introduce one.

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

<T is ClassTypeA>
<T is InterfaceTypeA>

<T is ClassTypeA>
<T is InterfaceTypeA>

Although extendsbrings some mess when it goes along with an interface, it's a broader term and it can be used to describe both cases. Try to tune your mind to the concept of extending a type(not extending a class, not implementing an interface). You restrict a type parameter by another typeand it doesn't matter what that type actually is. It only matters that it's its upper boundand it's its supertype.

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

回答by zhangde

In fact, when using generic on interface, the keyword is also extends. Here is the code example:

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

There are 2 classes that implements the Greeting interface:

有 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 ");
    }
}

And the test code:

和测试代码:

@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();
}