public void run(){
setFont("Courier-24");
//Define list as ArrayList<Integer>
ArrayList<Integer> list = new ArrayList<Integer>();
readList(list);
}
private void readList(ArrayList list){
list.add("Hello");
list.add(2);
println("list = "+list);
println("Type of list = "+list.get(0).getClass());
println("Type of list = "+list.get(1).getClass());
}
结果:
list = [你好,2]
list的类型= class java.lang.String
列表类型=类java.lang.Integer
这是我的代码和结果。我的问题是,Integer类型的ArrayList如何可以存储String对象?现在列表的类型是什么?这是什么机制?
答案 0 :(得分:6)
Java的泛型实际上并没有改变底层的类或对象,它们只是提供(大部分)围绕它们的编译时语义。
通过将ArrayList<Integer>
传递给期望ArrayList
(可以容纳任何)的方法,您将绕过编译器为您提供该类型安全性的能力。
Java Generics Tutorial解释了这一点,以及Java为何以这种方式实现泛型。 This page特别关注它:
泛型被引入到Java语言中,以便在编译时提供更严格的类型检查并支持泛型编程。为了实现泛型,Java编译器将类型擦除应用于:
- 如果类型参数是无界的,则将泛型类型中的所有类型参数替换为其边界或对象。因此,生成的字节码只包含普通的类,接口和方法。
- 如有必要,插入类型转换以保护类型安全。
- 生成桥接方法以保留扩展泛型类型中的多态性。
类型擦除确保不为参数化类型创建新类;因此,泛型不会产生运行时开销。
没有说的是,这也允许使用泛型(如run
)编写的代码与不带泛型的代码进行交互(如你的readList
),这对于一个具有庞大库基础的非常成熟的语言添加一个特性非常重要(就像在向Java中添加泛型一样)。
答案 1 :(得分:3)
宣布:
private void readList(ArrayList list)
您没有为此ArrayList
指定任何类型,因此默认情况下它的类型为Object
。
String
和Integer
(实际上是java中的所有类)都是Object
的子类型。因此可以将它们添加到列表中。
有关没有类型的泛型的更多信息,请阅读here。简而言之,泛型类型仅用于编译时间检查,因此您不会添加错误的类型(这可能会导致异常。在这种情况下,您对String
和Integer
的操作是兼容的,所以幸运的是没有错误)。
答案 2 :(得分:1)
在您的colorControlActivated
方法参数中,您尚未将其约束为readList
个值类型,因此Integer
无法获得编译带来的好处时间检查,必须求助于运行时类型检查。
答案 3 :(得分:1)
声明
ArrayList list
方法readList中的等同于
ArrayList<Object> list
很明显,String是Object,还有Integer。当传递给println时,两者都将使用自己的方法进行处理。
答案 4 :(得分:1)
我认为没有作为参数传递的泛型规范的ArrayList类型可以作为ArrayList。 String和Integer都继承了Object,因此它们都可以添加到列表中。但是,ArrayList元素的类型为Objects。