在Java中使用always "extends"有特殊的原因吗?而不是"implements"用于定义类型参数的边界?
extends
implements
例如:
public interface C {} public class A<B implements C>{}
是禁止的,但是
public class A<B extends C>{}
是正确的。原因是什么?
在泛型约束语言中,类是“实现”还是“扩展”在语义上没有区别。约束的可能性是“extends”和“super”——也就是说,这个类是否可以赋值给另一个类(extends),或者这个类是否可以从那个类(super)赋值。
基类型可能是一个泛型参数,因此实际类型可能是一个类的接口。考虑:
class MyGen<T, U extends T> {
此外,从客户端代码的角度来看,接口几乎与类难以区分,而对于子类型来说,它很重要。
B也可以是一个接口。"extends"用于定义子接口和子类。
interface IntfSub extends IntfSuper {} class ClzSub extends ClzSuper {}
我通常认为“Sub extends Super”是“子类似超级,但具有额外的功能”,而“Clz实现Intf”是“Clz是Intf的实现”。在你的例子中,这将匹配:B类似于C,但具有额外的功能。这里相关的是功能,而不是实现。
下面是一个更复杂的例子,说明在哪里允许扩展,以及可能需要什么:
public class A<T1 extends Comparable<T1>>
使用哪个术语有点随意。两种情况都有可能。也许语言设计者认为“扩展”是最基本的术语,而“实现”是接口的特殊情况。
但我认为implements会更有意义。我认为这更多地传达了参数类型不一定是继承关系,它们可以是任何类型的子类型关系。
Java术语表表示类似的观点。
答案在在这里中:
要声明一个有界类型参数,列出类型参数的名称,后跟extends关键字,再后跟它的上界[…]。注意,在这个上下文中,extends在一般意义上用于表示extends(如类)或implements(如接口)。
所以你知道了,这有点令人困惑,甲骨文知道这一点。
我们习惯了
class ClassTypeA implements InterfaceTypeA {} class ClassTypeB extends ClassTypeA {}
任何对这些规则的轻微偏离都会让我们感到困惑。
类型绑定的语法定义为
TypeBound: extends TypeVariable extends ClassOrInterfaceType {AdditionalBound}
(JLS 12 > 4.4。类型变量> TypeBound
TypeBound
如果要改变它,我们肯定会添加implements大小写
TypeBound: extends TypeVariable extends ClassType {AdditionalBound} implements InterfaceType {AdditionalBound}
最后得到两个处理相同的子句
ClassOrInterfaceType: ClassType InterfaceType
(JLS 12 >参考类型和值> ClassOrInterfaceType)
ClassOrInterfaceType
除了我们还需要照顾implements,这将使事情更加复杂。
我相信这就是为什么使用extends ClassOrInterfaceType而不是extends ClassType和implements InterfaceType的主要原因——在复杂的概念中保持简单。问题是我们没有合适的词来涵盖extends和implements,我们肯定不想引入一个。
extends ClassOrInterfaceType
extends ClassType
implements InterfaceType
<T is ClassTypeA>
<T is InterfaceTypeA>
虽然extends在与接口一起使用时会带来一些混乱,但它是一个更广泛的术语,可以用来描述两种情况。试着把你的思想调整到扩展类型的概念上(不是扩展一个类,不是实现接口)。你通过另一种类型来限制一个类型参数,这个类型实际上是什么并不重要。重要的是它是上界和超类型。
事实上,在interface上使用generic时,关键字也是扩展。下面是代码示例:
有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(); }
在<T中使用“extends”是数据类型本身直接实现Comparable,或者扩展实现Comparable的类的承诺。您可能已经编写了实现Comparable的另一个类a的子类B,如果您声明您的数据类型扩展Comparable>那么在实例化该类时,您可以使用a或B作为您的数据类型。