从一篇博客上看到的,但是博主只是说类型擦除导致出错。
package simplejava;
import java.util.ArrayList;
public class ErasedTest {
public static void main(String[] args) {
ArrayList<String> arr = new ArrayList<String>();
arr.add("a");
arr.add("b");
accept(arr);
}
public static void accept(ArrayList<Object> al) {
for (Object o : al)
System.out.println(o);
}
}
我的理解是:泛型是编译的时候不同,运行时被擦除为原生类型,也就是 main 方法中的变量 arr 的类型变成了 ArrayList,accept 方法中的参数 al 的类型也同样变成了 ArrayList,既然这样,为什么编译的时候出现了这样的错误:
error: incompatible types: ArrayList<String> cannot be converted to ArrayList<Object>
然后,如果在 accept 方法中的参数类型从ArrayList<Object> al
改成ArrayList al
,这样就可以编译通过了,这其中是什么原因的?
1
dreamerfable 2019-04-10 15:51:23 +08:00 1
运行时再编译期之后。运行时擦除,编译期还没有擦除,所以编译检查时就报错了。
|
2
peyppicp 2019-04-10 16:01:12 +08:00 1
1 都说得对
|
3
exonuclease 2019-04-10 16:40:30 +08:00
编译的时候只需要静态分析的时候就能看到这个错误 运行时是没有这个类型信息的
|
4
letianqiu 2019-04-10 18:43:08 +08:00 1
ArrayList<Object>和 ArrayList<String>是没有关系的,所以会报类型不匹配的错误。ArrayList 可以理解为 ArrayList<?>。
|
5
wsxyeah 2019-04-10 20:30:19 +08:00 via iPhone
ArrayList<Object> 是允许 add 一个 Object 进去的,ArrayList<String> 不行
|
6
nicreve 2019-04-10 20:31:00 +08:00 1
这个其实是 Java 里协变的概念。
List 不是协变的,即 A 是 B 的子类不等于 A 的 List 是 B 的 List 的“子类” List。 而数组是协变的,所以把例子里的 List 改成数组就不会报错。 |
7
geelaw 2019-04-10 20:36:07 +08:00
正确写出类型不安全的代码的方式是这样的:
ArrayList<String> stringList = new ArrayList<String>(); ArrayList erasedList = (ArrayList)stringList; erasedList.add(new Integer(0)); |
8
shalk 2019-04-10 20:53:55 +08:00 1
|
9
dadadajiba 2019-04-10 21:00:47 +08:00
https://www.v2ex.com/t/553854#reply1 被骗钱了,大家帮忙看看想想办法
|
10
staticer 2019-04-10 21:42:23 +08:00
ArrayList<Object>和 ArrayList<String>是没关系的。
设想一下,假如 ArrayList<Object>可以引用 ArrayList<String>。 那么,假如 void accept(ArrayList<Object> al){ al.add(new Object()); } 那么 accept(一个 ArrauList<String>对象)是不合理的。 |
11
Leammin 2019-04-11 01:02:17 +08:00 via Android 1
其实泛型要结合历史原因才比较好理解:以前是没泛型的,以前的 ArrayList 就是现在不带尖括号(泛型)的 ArrayList,存取对象直接就是 Object,但是每次取出对象都要进行强转类型,又因为一个 list 装的总是同一个类型的元素,所以有大量重复代码。因此后来增加了泛型,由*编译器*来帮我们做限制存取类型和强转类型的工作,如果类型不匹配,是由编译器给我们报错。
可以这么理解:泛型仅仅是为了在编译时帮我们做限制类型和强制转换类型,而不会存储泛型类型(尖括号里边的 T )的任何信息(包括是否父子类等信息)。所以说 ArrayList、ArrayList<Object>、ArrayList<String>是同一个类型,但是因为编译器帮我们做了类型限制,所以 ArrayList<Object>和 ArrayList<String>之间是不能互相转换的;而 ArrayList 不带任何泛型表示不接受类型限制,所以另外两个可以直接转换为它,但它不能直接转换为那两个;这也是为了兼容以前没有泛型时的写法,现在不推荐这种写法,如果不能确定类型,那么可以使用 ArrayList<?>。 |
12
king1101 OP 懂了,谢谢大家
|
13
Saltyx 2019-04-11 12:13:18 +08:00 via Android
泛型是不可变的
|