Java Generics通配符扩展了最终类

时间:2013-07-31 12:25:58

标签: java generics

为什么Java在编译TestGenerics class时没有发出任何警告,因为String classfinal并且无法扩展?

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

3 个答案:

答案 0 :(得分:7)

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

public List<? extends T> filterOutNulls(List<T> input) { ...

当然,这不是世界上最好的签名,但仍然完全合法。如果我将List<String>传递给该方法会发生什么?根据签名,它返回List<? extends String>。如果Java不允许使用该类型,则不可能将此方法用于List<String>(或者至少,不可能使用返回值)。

其次,extends语法在这种情况下仍然有用,因为List<String>List<? extends String>有不同的限制 - 具体来说,除了{{1}之外,你不能添加任何内容文字到null。我有时会使用List<? extends String>来表示集合是只读的(因为您可以传入的唯一? extendsT),而null表示写入 - 只有(因为你只能? super作为T)。这不是完全万无一失的(你仍然可以调用删除方法,传递Object,传播,等等),但是可以温和地提醒你如何使用该集合。

答案 1 :(得分:6)

编译器并没有真正注意到这一事实,因为它并不重要。列表中仍然允许String,在最终产品中,找不到任何扩展String的可能性。在erasure之后,它出现如下:

public void addStrings(List list)

正如您所看到的,现在没有关于扩展String的课程的建议。如果你创建了一个扩展String的类,那将是一个编译错误。没有必要让javac担心这一点。

答案 2 :(得分:0)

类型系统不考虑List<String>List<? extends String>等价,即使在编译时,String没有自身以外的子类型,因此任何对象都是{{ 1}}也必须是List<? extends String>

一种解释是List<String>不是最终的 - 可以从类中删除final,但不应该破坏任何内容:http://docs.oracle.com/javase/specs/jls/se7/html/jls-13.html#jls-13.4.2

类型系统考虑final并不是没有先例;例如,我们不能将final强制转换为String,因为编译器认为如果对象是Runnable,则它不能是实现String的某个未知子类。 / p>

如果我们希望泛型也能做出类似的推理并推断RunnableList<String>是等价的,那么打字规则会更加复杂。