使用接口而不是类定义通用

时间:2011-08-21 19:34:55

标签: java class generics inheritance interface

如何以类型安全的方式指定我希望在A内允许任何实现List接口的对象?我希望能够在所有对象上调用A的给定方法,关于它们是Class类型。

public interface A (){}

List<? extends A> myList = new ArrayList<? extends A>();

我得到:Cannot instantiate the type ArrayList<? extends A>

如果我将通用版离开实例化方面它可以正常工作,但是我必须指定@SuppressWarnings({ "rawtypes", "unchecked" })以使编译器对警告进行缄默。

5 个答案:

答案 0 :(得分:3)

要了解为什么实例化new ArrayList<? extends A>()没有意义,实际上我们可以用任意类或接口new ArrayList<B>()等效地创建B(即使不是与任何对象相关的,实现A,并且可以将生成的创建的ArrayList安全地分配给类型为ArrayList<? extends A>的变量。然后你可能想知道,哦,这是愚蠢的,因为我想要放入它的对象不属于B类,那么这又怎么样呢?但它 是相同的,因为无论如何你都不能把任何东西放入Something<? extends A>类型的引用中。这就是创建new ArrayList<? extends A>()

没有意义的原因
  

如何指定我想要任何实现A的对象   以类型安全的方式允许在List内部使用的接口?一世   希望能够在所有对象上调用A的给定方法,   关于他们是什么类型。

这正是ArrayList<A>的内容。它允许A的所有实例(当然,实现A的所有对象都是A的实例),您可以在它们上使用A的任何方法。这样的事情就是你想要的:

List<A> myList = new ArrayList<A>();

List<? extends A>之类的东西仅用于从其他代码获取List对象的情况,而您不知道(或关心)他们创建的通用参数究竟是什么。 (在这种情况下,您无法将对象放入List中。)这与您的情况完全不同,其中正在创建List对象,因此您决定并因此确切地知道使用了哪个泛型参数

答案 1 :(得分:2)

该问题与将类型参数绑定到接口无关,但是您无法使用通配符实例化参数化类型。 new ArrayList<? extends A>()甚至new ArrayList<?>()没有意义,因为您没有告诉编译器实例化的List实际上是什么。另一方面,new ArrayList<A>()会有意义。

答案 2 :(得分:1)

只需List<A>就可以了,它允许在列表中实现A的对象以及列表中的所有对象实现A

答案 3 :(得分:0)

我认为你在寻找:

List<? super A> myList = new ArrayList<A>();
  1. 列表与LT ;?扩展A> myList ...告诉编译器它是一个未指定类型的列表,未指定的类型扩展A.您不能在此列表中放置任何A,因为它可能不是正确的类型。所有编译器都知道这个列表中的任何对象都必须是A.我认为你想要List&lt;?超级A&gt;我的列表。这告诉编译器List是某些未指定类型的A扩展。现在编译器可以让我把任何A放在列表中。
  2. new ArrayList&lt;?扩展A&gt;();是完全错的。

答案 4 :(得分:0)

你想要

列表&lt; A&gt; collection = new ArrayList&lt; A&gt; ();

通过使用通配符,您可以抑制编译器的信息。你说你希望能够同时读写'List'。通用'? super A'允许您写入集合但不能从中读取。通用'? extends A'允许您从集合中读取但不写入它。在通用参数中加上'A'可以让您读取和写入集合。请参阅Joshua Bloch在http://java.sun.com/docs/books/effective/generics.pdf上关于泛型的开创性 Effective Java 的免费章节。