我正在从DotNet转向java,这种扩展的想法是新的。
我看到一些帖子完全解释了使用List<? extends SomeAbstract>
与List<? super SomeAbstract>
与List<SomeAbstract>
的对比,但我猜测使用和不使用之间没有区别延伸到泛型。
这是真的吗?如果使用抽象类作为父类,答案会改变吗?
class My_AbstractExtends<T extends SomeAbstract>
VS
class My_Abstract<SomeAbstract>
按如下方式创建子类
class My_ChildExtends extends My_AbstractExtends<ConcreteChildOfSomeAbstract>
VS
class My_Child extends My_Abstract<ConcreteChildOfSomeAbstract>
答案 0 :(得分:8)
我猜你在谈论在类型参数声明中使用extends。在那种情况下:
class My_Abstract<T extends SomeAbstract>
有一个名为T
的有界类型参数,必须是SomeAbstract
或其某个子类型。
class My_Abstract<SomeAbstract>
有一个名为SomeAbstract
的无界类型参数,可以是任何东西。请注意,SomeAbstract
不再引用第一个示例使用的实际类型SomeAbstract
!
要进一步扩展:假设第二个声明是class My_Abstract<T>
。 T
显然有一个类型参数,而不是实际类型。但它不必被称为T
......它可以被称为E
或Bob
或SomeAbstract
。在所有这些情况下,它仍然只是一个类型参数...实际类型永远不会去那里,它也没有任何意义(类型参数的整个点是不引用特定类型,但而是在创建类的实例时允许其他类型放在其位置。)
在您编辑的代码中,将My_Child
的声明更改为
class My_Child extends My_Abstract<Object>
你会看到差异。如果你真的试图在第二个版本中使用类型参数SomeAbstract
做某事,你也会发现你不能调用真实SomeAbstract
类中声明的任何方法。这就是为什么你应该总是遵循使用单字母类型参数的惯例的一个很好的例子......如果你不这样做,那真是令人困惑。
这已经很长了,但我还要注意,所有这一切基本上与你问题的前半部分无关。像? extends SomeAbstract
和? super SomeAbstract
这样的通配符不用于类型参数声明(例如定义泛型类时使用的那些),它们主要用于方法参数。 List
是解释为什么需要通配符的典型示例,因为它作为对象容器的性质使其相对容易理解,但与它们相关的规则适用于任何泛型类型。我试图在this answer中以相对笼统的术语解释这一点。
答案 1 :(得分: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;
答案 2 :(得分:0)
在泛型类声明中使用extends
:
'?'当手头的代码不关心类型参数的特定类型时,关键字用在方法中,但只关心它上面的低(扩展)或上(超)绑定。
维基百科explains以非常实用的方式对不同结构的净效应。
要理解为什么需要几种不同的结构来指定泛型,你必须阅读covariance and contravariance,它们是存在泛型的静态类型安全规则的理论名称。