假设A
是一个接口。那么以下两种定义方式有什么区别:
public <T extends A> void foo(T t) { ... }
并且
public void foo(A a) { ...}
?
当使用一个对象时,没有什么区别。但是可以想象一下,如果你有:
class B extends A { ... }
并且
public void f(List<A> list) { ... };
并且
public <T extends A> void f(List<T> list) { ... };
第一个方法可以传递一个完全符合类型 List<A>
的列表。第二个方法可以传递包含扩展 A
对象的列表。然而,第一个方法不能做同样的事情。换句话说,你不能将 List<B>
传递给第一个方法,但可以传递给第二个方法。
没什么。
另一方面,考虑这种方法:
public <T extends A> T transform(T t);
并且调用者代码:
class B implements A { ... }
B result = transform(new B(...));
如果你将方法声明为以下形式,就不可能实现(因为编译器会强制你将 result
类型声明为 A
):
public A transform(A a)
f
代表什么? - Freewind在您的情况下没有区别,因为类型参数仅在一个地方使用。这两种方法都将接受任何A或扩展A的内容。在这种情况下,泛型方法更有意义,因为类型参数可以将返回值与传递的参数绑定:
public <T extends A> T f(Class<T>) {...}
这取决于函数内部的内容是否有所不同。
泛型的目的是确保类型安全。假设A有两个子类,我们称之为B和C。在第一个例子中,使用f(List<A>),列表可以包括B、C或两者混合。但在第二个例子中,f<T extends A>(List<T>),当我们调用函数时必须指定类型。如果我们说f<B>,那么我们知道这是一个B的列表,不允许出现C。我们将无法传递C或通用A的列表,不能添加任何C到列表中,我们取出的任何东西都保证是B。
这是好是坏取决于你想做什么。如果想要一个列表既可以是全部B也可以是全部C,那么泛型有助于保证这一点。如果想要一个可以混合两者的列表,则不应使用泛型,而应使用简单的f(List<A>)。
List<T>
或 List<A>
,只有 T
和 A
。 - newacct
public void f(List<? extends A> list);
。 - newacct