Java泛型和关键字

时间:2015-09-27 23:15:52

标签: java generics instanceof

所以,我正在查看Oracle Java教程,特别是这段代码;

List<EvenNumber> le = new ArrayList<>();
List<? extends NaturalNumber> ln = le;
ln.add(new NaturalNumber(35));  // compile-time error

可以找到here。这是我的理解(如果我错了,请纠正我)上面的代码不起作用,因为编译器不知道ln引用了EvenNumbers列表,所以这可以防止你意外添加任何可能是List的元素的超类型的对象。如果是这种情况,那么为什么如果你有一个类似Number num = new Integer(6);的语句,如果你编写if语句,编译器就能正确地确定num是一个Integer对象; if (num instanceof Integer) {...}

我想我的问题是,编译器如何确定num在第二个示例中引用Integer对象,但无法确定ln是否引用到第一个例子中的List<EvenNumber>对象?

3 个答案:

答案 0 :(得分:1)

你的两个例子是相反的。

Integer Number,所以

List<Number> list;
list.add(new Integer(1)); // compiles

EvenNumber NaturalNumber不是相反,所以

List<EvenNumber> list;
list.add(new NaturalNumber(1)); // compile error

因为EvenNumberNaturalNumberNaturalNumber 不是(必然)EvenNumber

如果你在参考案例中交换IntegerNumber然后重做它,它应该有意义,即这将编译:

List<NaturalNumber> list;
list.add(new EvenNumber(2)); // compiles OK

答案 1 :(得分:1)

通常,编译器能够确定很多东西,并在优化代码时使用它的观察结果。

但是,Java是statically and strongly类型语言,编译器在类型安全方面没有自由。

1)禁止添加ln列表,因为人们并不确切知道它应该包含哪种类型的元素。在您的示例中,此规则阻止将列表置于无效状态。

2)&#34; ...编译器能够正确地确定num是一个整数...&#34;

不正确,编译器不能确定它(尽管如果Java是弱类型语言的话,它可能会发生。)

3)num instanceof Integer

这是在运行时评估的,而不是在编译时评估的。但是,以下将产生编译时错误:

num instanceof String

因为Number永远不会是String

答案 2 :(得分:0)

无法编译的主要原因是? extends T的行为方式。一般来说,人们应该熟悉Producer Extends, Consumer Super或简称PECS。

现在,我还没有看过这个特定的代码示例,但我认为层次结构EvenNumber扩展了NaturalNumber。这使得赋值语句有效,因为EvenNumberNaturalNumber(尽管我打赌数学家正在嘲笑这个)。

在上面突出显示的场景中,您无法向集合添加任何内容的原因是它主要用于阅读。也就是说,列表是生成器,因此它与extends绑定。

如果你想同时阅读写一个集合,你只需要留下通配符。

你的第二个例子根本没有 nothing 与泛型有关,而是简单的继承。由于Integer继承自Number,我们可以说Integer是-a Number,因此可以视为数字。 继承的任何类都具有此功能。有关详细信息,请查看Liskov Substitution Principle