有什么区别:
static void findMax(LinkedList<? extends Number> list){...}
和:
static <T extends Number> void findMax(LinkedList<T> list){...}
由于两者都有效,我想知道两者之间是否有任何大的区别,建议使用哪个。
主要区别在于,在第二个版本中您可以访问该类型T
,而在第一个版本中您不能。
例如,您可能希望返回与 T 相关联的内容(例如返回 T 而不是 void):
static <T extends Number> T findMax(LinkedList<T> list){...}
或者您可能需要创建一个新的 T 列表:
static <T extends Number> void findMax(LinkedList<T> list){
List<T> copyAsArrayList = new ArrayList<> (list);
//do something with the copy
}
如果您不需要访问T
,则两个版本在功能上是等效的。
findMax
如果您只关心接受满足某些条件的列表(在您的情况下是扩展类型的列表),则应该使用第一个Number
。
static Number findMax(LinkedList<? extends Number> list) {
Number max = list.get(0);
for (Number number : list) {
if (number > max) {
max = number;
}
}
return max;
}
此方法返回Number
. 例如,如果您有一个自己的类扩展Number
并具有一些您希望稍后在此方法的结果上使用的特殊方法,这可能是一个问题。
T
当您计划在方法体中使用精确类型,作为方法参数或作为方法的返回类型时,应该使用第二个。
static <T extends Number> T findMax(LinkedList<T> list, T currentMax) {
T max = currentMax;
for (T number : list) {
if (number > max) {
max = number;
}
}
return max;
}
结论:
在功能上,它们几乎是等价的,只是无法修改具有未知类型 ( ) 的列表。?
这就是区别
static void findMax(LinkedList<? extends Number> list){
list.add(list.get(0)); <-- compile error
}
您不能在列表中添加除 null 之外的任何内容。
同时编译时没有错误或警告
static <T extends Number> void findMax2(LinkedList<T> list){
list.add(list.get(0)); <-- no error
}
就签名的力量而言,两者完全相同。我的意思是,如果您有任何使用第二个签名的 API,您可以将其替换为使用第一个签名的 API,并且使用该 API 的任何代码都可以像以前一样工作,任何以前不能工作的代码也不行。所以对于外部代码,两者没有区别。
您将如何将第二个的实施更改为第一个?其他人已经用list.add(list.get(0));
. 具有第一个签名的 API 可以执行该操作吗?是的。这很简单。只需让第一个调用第二个(将第二个变为内部私有方法)。这称为捕获助手。您可以这样做的事实证明,从外部代码的角度来看,两者都可以“做”相同的事情(通过任何内部方式“做”,包括调用其他方法)。
static void findMax(LinkedList<? extends Number> list){
findMaxPrivate(list);
}
static static <T extends Number> void findMaxPrivate(LinkedList<T> list){
list.add(list.get(0));
}
我认为关于第二种方法主体中参数 T 的访问已经有了很好的答案。
我想补充一点,如果您有许多需要按类型链接的参数,则需要第二种表示法。例子:
static <T extends Number> int getPosition(LinkedList<T> list, T element){...}
如果不使用泛型类型参数,您将无法强制执行上述约束<T>
。