泛型Java通配符和子类型

时间:2016-04-09 10:17:27

标签: java generics

我正在阅读Java atm中的Generics,如果有一些帮助,事情会变得有点慢。我从Oracles自己的数据库中读到:

https://docs.oracle.com/javase/tutorial/java/generics/subtyping.html

在底部,我们可以看到List<Integer>List<? extends Number>

的子类型

我也遇到过这个stackoverflow问题:

Java Generic type : difference between List <? extends Number> and List <T extends Number>

在一个答案中说:这是真的:

((List<Integer>)list).add((int) s);

我已经验证了,所以没关系。但我完全不了解它。

如果通配符是Short类并且我添加一个高于2 ^ 15-1(= 32767)的数字怎么办?它不应该给出错误吗?

我甚至尝试过类似的东西,但效果很好:

import java.util.*;
class CastingWildcard{
    public static void main(String[] args){
        List<? extends Number> list = new ArrayList<Short>();
        int s=32770;
        ((List<Integer>)list).add((int) s);
        System.out.println(list.get(0));
    }
}

总结一下:为什么我可以将List<? extends Number>转换为List<Integer>当通配符可能是短的,甚至是Byte,它也会扩展数字?

2 个答案:

答案 0 :(得分:1)

您可以将对象强制转换为您想要的任何对象,但它可能会在运行时失败。但是,由于在运行时期间不存在泛型信息,因此您的代码基本上变为((List)list).add(s);。此时list将使用任何对象,而不仅仅是Number。泛型可以帮助您避免强制转换并在编译期间保持类型安全,但在运行时它们不再重要。

答案 1 :(得分:1)

强制转换使编译器忽略了这样的事实,即类型可能无法分配。

在运行时,类型参数并不重要,请参阅type erasure

ArrayList在内部将内容存储在Object[]数组中,这意味着如果您“滥用”强制转换,则可以向列表对象添加任何引用类型。

您检索对象时可能会遇到异常,因为get语句中隐藏了强制转换。

示例:

List<Integer> list = new ArrayList<>(Arrays.asList(1, 2, 3));
List<String> list2 = (List) list;
list2.add("Hello World");

Integer i = list.get(0); // works
String s = list2.get(3); // works
s = list2.get(1); // ClassCastException
i = list.get(3); // ClassCastException