文章目录

  • 简介
  • 举个例子
  • 原因
  • 解决办法
  • 总结


java中的类型擦除type erasure


简介

泛型是java从JDK 5开始引入的新特性,泛型的引入可以让我们在代码编译的时候就强制检查传入的类型,从而提升了程序的健壮度。

泛型可以用在类和接口上,在集合类中非常常见。本文将会讲解泛型导致的类型擦除。

举个例子

我们先举一个最简单的例子:

@Slf4jpublic class TypeErase {public static void main(String[] args) {ArrayList<String> stringArrayList = new ArrayList<String>();stringArrayList.add("a");stringArrayList.add("b");action(stringArrayList);}public static void action(ArrayList<Object> al){for(Object o: al)log.info("{}",o);}}

上面的例子中,我们定义了一个ArrayList,其中指定的类型是String。

然后调用了action方法,action方法需要传入一个ArrayList,但是这个list的类型是Object。

乍看之下好像没有问题,因为String是Object的子类,是可以进行转换的。

但是实际上代码编译出错:

Error:(18, 16) java: 不兼容的类型: java.util.ArrayList<java.lang.String>无法转换为java.util.ArrayList<java.lang.Object>

原因

上面例子的原因就是类型擦除(type erasure)。java中的泛型是在编译时做检测的。而编译后生成的二进制文件中并不保存类型相关的信息。

上面的例子中,编译之后不管是ArrayList<String> 还是ArrayList<Object> 都会变成ArrayList。其中的类型Object/String对JVM是不可见的。

但是在编译的过程中,编译器发现了两者的类型不同,然后抛出了错误。

解决办法

要解决上面的问题,我们可以使用下面的办法:

    public static void actionTwo(ArrayList<?> al){for(Object o: al)log.info("{}",o);}

通过使用通配符?,可以匹配任何类型,从而通过编译。

但是要注意这里actionTwo方法中,因为我们不知道传入的类型到底是什么,所以我们不能在actionTwo中添加任何元素。

总结

从上面的例子我们可以看出,ArrayList<String>并不是ArrayList<Object>的子类。如果一定要找出父子关系,那么ArrayList<String>是Collection<String>的子类。

但是Object[] objArray是String[] strArr的父类。因为对Array来说,其具体的类型是已知的。

本文的例子https://github.com/ddean2009/learn-java-collections

©著作权归作者所有:来自51CTO博客作者ddean2009的原创作品,如需转载,请注明出处,否则将追究法律责任

更多相关文章

  1. 一文读懂java中的Reference和引用类型
  2. java 8中构建无限的stream
  3. Java泛型Type
  4. Spring注解 @Resource和@Autowired比较
  5. 面向对象系列教材 (二)- Java类的属性
  6. 变量系列教材 (四)- 在Java中进行基本类型的类型转换
  7. 变量系列教材 (三)- 什么是Java的字面值
  8. 变量系列教材 (二)- Java中有八种基本变量类型
  9. BRCM5.02编译五: fatal error: uuid/uuid.h: No such file or dir

随机推荐

  1. golang的编译器是什么
  2. golang 如何判断文件是否存在
  3. golang 管道线程安全吗
  4. golang的zap怎么使用
  5. golang 如何模块化
  6. golang调试工具有哪些?
  7. golang的slice如何去重
  8. golang判断map中指定key是否存在
  9. golang指针传递和值传递的区别是什么?
  10. golang的hashmap怎么扩容