10

TestGenerics class考虑到String classisfinal并且不能扩展,为什么 Java 在编译 my 时不会发出任何警告?

import java.util.*;
    public class TestGenerics { 
        public void addStrings(List<? extends String> list) {
          // some code here
        }
    }
}
4

3 回答 3

7

假设我有一个这样的方法:

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 等),但可以温和地提醒您如何使用该集合。nullList<? extends String>? extendsTnull? superTObjectnull

于 2013-07-31T12:44:39.713 回答
6

编译器并没有真正注意到这个事实,因为这无关紧要。String列表中仍然允许 s,并且在最终产品中,String没有发现任何扩展的可能性。擦除后,结果如下:

public void addStrings(List list)

如您所见,现在没有关于扩展类的建议String。如果您确实创建了一个扩展类String,那本身就是一个编译错误。javac 无需担心这一点。

于 2013-07-31T12:29:35.847 回答
0

类型系统不考虑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>是等价的,那么它将使打字规则更加复杂。

于 2013-08-01T01:51:01.457 回答