以下问题来自Kathy Sierra和Bert Bates的Java SCJP5一书。 给定一个声明为:
的方法public static <E extends Number> List<E> process(List<E> nums)
程序员想要使用这样的方法:
// INSERT DECLARATIONS HERE
output = process(input);
可以在// INSERT DECLARATIONS这里放置哪一对声明以允许代码编译? (选择所有适用的选项。)
一个。
ArrayList<Integer> input = null;
ArrayList<Integer> output = null;
乙
ArrayList<Integer> input = null;
List<Integer> output = null;
下进行。
ArrayList<Integer> input = null;
List<Number> output = null;
d
List<Number> input = null;
ArrayList<Integer> output = null;
电子。
List<Number> input = null;
List<Number> output = null;
F。
List<Integer> input = null;
List<Integer> output = null;
-G。以上都不是。
给出的正确答案是:B,E,F和书中的解释说明:
“返回类型肯定被声明为List,而不是ArrayList,因此A,D是错误的。......”
这是我没有得到的......为什么返回类型必须只是List而不是ArrayList?就像参数可以是ArrayList那么为什么cant返回类型也是arrayList?
由于
答案 0 :(得分:13)
因为ArrayList是List的子类,所以进程返回的List不能保证是ArrayList。例如,它可能是LinkedList。
答案 1 :(得分:3)
当您指定List类型的返回时,您说返回可以是任何类型的List,无论它是ArrayList,LinkedList还是其他类型的List。如果你试图返回一个ArrayList,那你就太具体了 - 它不再是一个通用的List。
答案 2 :(得分:3)
这实际上并非特定于泛型,而是处理类型。
简单的方法是,ArrayList
是List
,但List
不一定是ArrayList
。
ArrayList
实现了List
接口,因此可以将其视为List
。但是,仅仅因为某些内容实现了List
,它就不是ArrayList
。例如,LinkedList
实现List
,但不是ArrayList
。
例如,允许以下内容:
List arrayList = new ArrayList();
List linkedList = new LinkedList();
这是因为ArrayList
和LinkedList
都实现了List
接口,因此它们都可以作为List
来处理。
但是,不允许以下内容:
ArrayList arrayList = new LinkedList();
虽然ArrayList
和LinkedList
都实现List
,但它们不是同一个类。它们可能通过实现List
的方法具有相似性,但它们是完全独立的类。
答案 3 :(得分:3)
返回类型可以是一个ArrayList,但它也可以不是ArrayList,它可以是LinkedList,也可以是某些Collections List包装器或其他东西。为了将它分配给变量,您必须使用它可能的最高级别类型(在这种情况下为List)或者如果您知道必须是一个ArrayList,则需要向下转换。
实际上,变量应该几乎总是输入List(如果不是Collection)。实际上几乎没有理由为这些类引用具体类型。
我能想到的唯一原因是,如果你有一个方法需要随机访问List,并且你想确保你没有因为性能原因而得到LinkedList而且List太大而无法合理地复制到ArrayList为了随机访问。
答案 4 :(得分:1)
process
方法无法决定选择哪个具体的List实现。它的签名给你一个承诺,它将能够在任何列表(ArrayList,LinkedList等)上操作,并且只能指定返回值将是SOME List。
例如,如果返回的对象是LinkedList,则无法将其直接分配给声明为ArrayList的变量,但您可以将其视为List。因此A.和D.不正确。您不能将变量声明为ArrayList。
答案 5 :(得分:1)
您可以将返回类型声明为ArrayList
,但它需要显式强制转换,如下所示:
ArrayList output = null;
output = (ArrayList)process(input);
......这与仿制药允许你完成的事情相反。
答案 6 :(得分:0)
这是因为问题明确表示该方法返回List&lt; T&gt;。您可以很好地更改方法定义以返回ArrayList&lt; T&gt;,但这是一个不同的问题。列表&lt; T&gt;可以是许多不同类型的列表。
答案 7 :(得分:0)
另一种看待它的方法是“赋值兼容性”。语义上,方法调用
output = process(input)
相当于
nums = input;
/* body of process... */
output = returnVal; /* where process exits with "return returnVal" */
我们知道nums
的类型为List<E>
,因此input
的类型必须“可分配”给List<E>
。同样,我们知道returnVal
(即process
)类型List<E>
的返回值,因此List<E>
必须“{可分配”到output
的类型。
通常,如果T
是U
的子类型,T
类型可以“分配”到U
类型(包括T
的情况和U
是一样的)。
因此,input
的类型必须为List<E>
或List<E>
的子类型(例如ArrayList<E>
或LinkedList<E>
)。同样,output
的类型必须为List<E>
或List<E>
的超类型(例如,Collection<E>
或甚至Object
)。