TestGenerics
class
考虑到String
class
isfinal
并且不能扩展,为什么 Java 在编译 my 时不会发出任何警告?
import java.util.*;
public class TestGenerics {
public void addStrings(List<? extends String> list) {
// some code here
}
}
}
假设我有一个这样的方法:
public List<? extends T> filterOutNulls(List<T> input) { ...
诚然,这不是世界上最好的签名,但仍然完全合法。如果我将 a 传递List<String>
给该方法会发生什么?根据签名,它返回一个List<? extends String>
. 如果 Java 不允许该类型,则无法使用此方法List<String>
(或至少无法使用返回值)。
其次,extends
在这种情况下,语法仍然很有用,因为List<String>
和有不同的限制——特别是,除了文字List<? extends String>
之外,你不能添加任何东西到. 我有时会用来表示一个集合是只读的(因为你可以传入的唯一 s are ),并表示只写的(因为你只能将s 输出为)。这并不完全是万无一失的(您仍然可以调用 remove 方法、传入s、downcast 等),但可以温和地提醒您如何使用该集合。null
List<? extends String>
? extends
T
null
? super
T
Object
null
编译器并没有真正注意到这个事实,因为这无关紧要。String
列表中仍然允许 s,并且在最终产品中,String
没有发现任何扩展的可能性。擦除后,结果如下:
public void addStrings(List list)
如您所见,现在没有关于扩展类的建议String
。如果您确实创建了一个扩展类String
,那本身就是一个编译错误。javac 无需担心这一点。
类型系统不考虑List<String>
和List<? extends String>
等价,即使在编译时,String
除了自身没有子类型,因此任何为 a 的对象也List<? extends String>
必须是 a List<String>
。
一种解释是这final
不是最终的 - 可以final
从类中删除并且什么都不会破坏:http://docs.oracle.com/javase/specs/jls/se7/html/jls-13.html#jls-13.4。 2
类型系统的考虑并非没有先例final
。例如,我们不能将 a 强制String
转换为 a Runnable
,因为编译器认为如果一个对象是String
,它不可能是某个未知的子类实现了Runnable
。
如果我们希望泛型也可以进行这样的推理并推断出它List<String>
并且List<? extends String>
是等价的,那么它将使打字规则更加复杂。