<T extends A> void foo(T t>和void foo(A a)之间的区别

7

假设A是一个接口。那么以下两种定义方式有什么区别:

public <T extends A> void foo(T t) { ... }

并且

public void foo(A a) { ...}

?

4个回答

8

当使用一个对象时,没有什么区别。但是可以想象一下,如果你有:

class B extends A { ... }

并且

public void f(List<A> list) { ... };

并且

public <T extends A> void f(List<T> list) { ... };

第一个方法可以传递一个完全符合类型 List<A> 的列表。第二个方法可以传递包含扩展 A 对象的列表。然而,第一个方法不能做同样的事情。换句话说,你不能将 List<B> 传递给第一个方法,但可以传递给第二个方法。


1
对于第二种情况,您仍然可以编写 public void f(List<? extends A> list); - newacct

7

没什么。

另一方面,考虑这种方法:

public <T extends A> T transform(T t);

并且调用者代码:

class B implements A { ... }
B result = transform(new B(...));

如果你将方法声明为以下形式,就不可能实现(因为编译器会强制你将 result 类型声明为 A):

public A transform(A a)

如果您有返回类型,这也是正确的。 - Amir Raminfar
你声明了变量f吗?f代表什么? - Freewind

4

在您的情况下没有区别,因为类型参数仅在一个地方使用。这两种方法都将接受任何A或扩展A的内容。在这种情况下,泛型方法更有意义,因为类型参数可以将返回值与传递的参数绑定:

public <T extends A> T f(Class<T>) {...}

0

这取决于函数内部的内容是否有所不同。

泛型的目的是确保类型安全。假设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>)。


你指的是哪些例子? - newacct
我所说的“例子”是原帖提供的两个函数声明:“<T extends A> f(List<T>)”和“f(List<A>)”。好吧,也许它们并不是真正的“例子”。 - Jay
我在问题中没有看到这个,只在一个答案中看到了。 - newacct
问题开始说,“假设 A 是一个接口。那么以下示例中的函数声明有什么区别?”然后给出第一个被称为“示例”的函数声明。接下来说“或者”,并给出下一个示例。你的浏览器无法正确显示这段文字吗?还是我们之间出现了误解? - Jay
他的问题中没有 List<T>List<A>,只有 TA - newacct
抱歉!在问题和答案之间来回切换时,我混淆了一个答案和原始问题!好吧,这个问题已经过时了,更新我的答案以澄清除了这个评论之外的内容似乎没有意义。 - Jay

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接