据我所知,使用上限有限泛型并使用超类作为方法参数都接受相同的可能参数。哪个是首选,两者之间有什么区别?如果有的话?
上限有限泛型作为参数:
public <T extends Foo> void doSomething(T foo) {}
超类作为参数:
public void doSomething(Foo foo) {}
答案 0 :(得分:6)
这是一个上限类型参数。使用super
创建下限,您无法真正为类型参数执行此操作。 You can't have a lower bounded type parameter。
如果您想要传递List<T>
,那将会产生影响。因此,对于以下两种方法:
public <T extends Foo> void doSomething(List<T> foos) {}
public void doSomething(List<Foo> foo) {}
对于给定的班级:
class Bar extends Foo { }
以下方法调用:
List<Bar> list = new ArrayList<Bar>();
doSomething(list);
对第一种方法有效,但对第二种方法无效。第二种方法失败,因为List<Foo>
不是List<Bar>
的超类型,尽管Foo
是超级类型的Bar
。但是,第一种方法通过,因为类型参数T
将被推断为Bar
。
答案 1 :(得分:1)
通常,只有在类/方法/字段声明中的多个位置使用时才需要类型变量。当你在方法(而不是类)上声明一个时,唯一使用它的地方是参数和该方法的返回值。
例如,您可以在多个参数上使用它以确保其类型匹配:
public static <T> void addToList(List<T> list, T element) {
list.add(element);
}
这是一个简单的例子,但你可以看到它阻止你给它一个与列表的通用类型不匹配的元素:
List<Integer> list = new ArrayList<>();
addToList(list, 7);
//addToList(list, 0.7); // doesn't compile
//addToList(list, "a"); // doesn't compile
您还可以将参数和返回类型声明为相同的类型:
public static <T> T nullCheck(T value, T defValue) {
return value != null ? value : defValue;
}
由于此方法返回了它给出的两个T
对象中的一个,我们可以放心地说返回的对象也是T
类型。
Integer iN = null;
Integer i = nullCheck(iN, 7);
System.out.println(i); // "7"
Double dN = null;
Double d = nullCheck(dN, 0.7);
System.out.println(d); // "0.7"
Number n = nullCheck(i, d); // T = superclass of Integer and Double
System.out.println(n); // "7"
对于问题中的示例,类型变量仅使用一次,因此它等同于使用超类。在这种情况下,你应该避免声明一个类型变量,它只是不必要的混乱。
另外我应该注意,另一个答案更改了使用List<T>
和List<Foo>
的示例,但正如评论中所提到的,超类实际上是List<? extends Foo>
,所以没有类型变量是也需要那里。