从一篇博客上看到的,但是博主只是说类型擦除导致出错。
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"); acceptarr); } 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 ![]() 运行时再编译期之后。运行时擦除,编译期还没有擦除,所以编译检查时就报错了。 |
2 peyppicp 2019-04-10 16:01:12 +08:00 ![]() 1 都说得对 |
3 exonuclease 2019-04-10 16:40:30 +08:00 编译的时候只需要静态分析的时候就能看到这个错误 运行时是没有这个类型信息的 |
4 letianqiu 2019-04-10 18:43:08 +08:00 ![]() 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 ![]() 这个其实是 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 ![]() |
![]() | 9 dadadajiba 2019-04-10 21:00:47 +08:00 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 ![]() 其实泛型要结合历史原因才比较好理解:以前是没泛型的,以前的 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 泛型是不可变的 |