4

我正在从 DotNet 转到 java,这种扩展的想法是新的。

我看过一些完全解释使用List<? extends SomeAbstract>vs. List<? super SomeAbstract>vs.的帖子List<SomeAbstract>,但我猜在泛型中使用和不使用扩展之间没有区别。

真的吗?如果使用抽象类作为父类,答案会改变吗?

class My_AbstractExtends<T extends SomeAbstract>

对比

class My_Abstract<SomeAbstract>

编辑

创建子类如下

class My_ChildExtends extends My_AbstractExtends<ConcreteChildOfSomeAbstract>

对比

class My_Child extends My_Abstract<ConcreteChildOfSomeAbstract>
4

3 回答 3

8

我猜你说的是在类型参数声明中使用扩展。在这种情况下:

class My_Abstract<T extends SomeAbstract>

有一个有界类型参数,称为T它必须是SomeAbstract它的某个子类型。

class My_Abstract<SomeAbstract>

有一个无界类型参数,称为SomeAbstract可以是任何东西。请注意,SomeAbstract不再指SomeAbstract第一个示例使用的实际类型!

对此进行扩展:想象一下,如果第二个声明是class My_Abstract<T>. T显然有一个类型参数,而不是实际类型。但它不必被调用T......它可以被调用Eor Bobor SomeAbstract。在所有这些情况下,它仍然只是一个类型参数......一个实际的类型永远不会去那里,也没有任何意义(类型参数的重点是不引用特定类型,而是而是允许在创建类的实例时将其他类型放在其位置)。

在您编辑的代码中,将My_Child' 声明更改为

class My_Child extends My_Abstract<Object>

你会看到区别。如果你真的尝试在第二个版本中使用类型参数做某事SomeAbstract,你还会发现你无法调用在真实SomeAbstract类中声明的任何方法。这就是为什么您应该始终遵循使用单字母类型参数的约定的一个很好的例子……如果您不这样做,那真的很混乱。

这真的很长,但我也想指出,所有这些基本上与你问题的前半部分无关。通配符喜欢? extends SomeAbstract? super SomeAbstract不在类型参数声明中使用(例如在定义泛型类时使用的通配符),它们主要用于方法参数。List是解释为什么需要通配符的典型示例,因为它作为对象容器的性质使其相对容易理解,但与它们有关的规则适用于任何泛型类型。我试图在这个答案中用相对笼统的术语来解释这一点。

于 2011-06-15T16:38:16.523 回答
2

它可以让您T在其他地方参考。

public class A<T extends SomeClass>{
    public A(T x){this.x=x;}
    public T x;
}

然后你的类的用户可以使用他们原来的类型,而不必使用 SomeClass。

MyObject x = new A<MyObject>(new MyObject()).x;
于 2011-06-15T16:58:50.827 回答
0

extends在泛型类声明中使用:

  1. 将可用作参数的类型限制为继承自扩展类的类型。
  2. 允许泛型类调用扩展类中声明的方法。

这 '?' 当手头的代码不关心类型参数的特定类型,而只关心其上的下限(扩展)或上限(超级)时,在方法中使用关键字。

维基百科以非常务实的方式解释了不同结构的净效应。

要了解为什么需要几种不同的构造来指定泛型,您必须阅读协变和逆变,它们是存在泛型时静态类型安全规则的理论名称。

于 2011-06-16T12:24:33.807 回答