对于java 泛型 编译时处理,运行时擦除的特点理解

  • 对于编译时处理

    • 在使用泛型相关的类或方法时,如果声明时的类型和具体使用时的类型不一致则直接会编译不通过
  • 对于运行时擦除
    • 当在运行时对两个相同类型但泛型的具体类型不同时,在运行时实际都是操作的相同的类型,而不会体现出来泛型的的具体类型;

    

public static void main(String[] args){

      List a = Collections.emptyList();
List b = Collections.emptyList();
// true , 对于不包含泛型初始化的list实际都是使用的相同的实例数据
LOGGER.info(String.valueOf(a == b)); List<String> a1 = Collections.emptyList();
boolean v = a == a1;
// true, 对于 a 和 a1 两个参数的类型实际是不同的,但在运行时实际是对于a和a1的类型实际都是相同的List类型; 可以通过 javap -v 类名 来查看编译后的class文件
LOGGER.info(String.valueOf(v)); List<Integer> b1 = Collections.emptyList();
// 由于a1和b1的泛型的具体类型不一致,因此在编译时不会通过
// boolean v1 = a1 == b1
}

  对于泛型的显式限定和隐式限定区别

 public static void castQuestion() {
// 在执行实例化操作时,实际已经隐式限定了当前对象的类型
// 在执行具体操作时,虽然根据变量的限定符显式定义,但在实际使用中就会抛出错误
Container<StringBuilder> stringContainer = new Container("1");
StringBuilder element = stringContainer.getElement(); } // 自定义内部容器类,类型为泛型
// 单界限操作: E extends CharSequence,这里限定了泛型的类型只能为CharSequence的子级
public static class Container<E extends Serializable> {
private E element; public Container(E element) {
this.element = element;
// 可以看到当前元素的实际类型
System.out.println(element.getClass().getTypeName());
} // 方法
public E getElement() {
return element;
} public void setElement(E element) {
this.element = element;
}
}

  可以看到在指定 new 时未显式指定对象元素类型,但通过调用有参构造方法实际已限定了当前对象的element元素类型;

  虽然对象变量显式限定了当前变量的泛型,对于操作方法实际是根据调用者的具体泛型类型进行限制,因此可以看到 "StringBuilder element = stringContainer.getElement();" 返回值类型为 StringBuilder;

  而由于对象中的实际类型为String类型,当将String类型强制赋值为Integer类型数据时,就会抛出ClassCastException

由于泛型存在编译时校验,运行时擦写的特点,因此为了保证运行时也提供泛型类型校验, 在Collections中提供了 checked*的工具类,在执行操作时保证了运行时的类型校验

    public void collectionGenericType() {
List<Integer> integers = new ArrayList<>(Arrays.asList(1, 2, 3, 4));
// 由于泛型存在编译时校验,运行时擦写
List noGenericTypeList = integers;
System.out.println(noGenericTypeList == integers);
// 虽然 noGenericTypeList 引用了 integers
// 运行时泛型擦写 List<Integer> -> List<Object> -> List
// 因此可以写入任意类型的数据
noGenericTypeList.add("A");
// 由于数据读取时需要进行类型转换(转换为泛型的指定类型)因此会抛出ClassCastException
// integers.forEach(System.out::println);
// 而对于noGenericTypeList由于没有泛型的约束,因此读取数据是都是按照Object类型处理
noGenericTypeList.forEach(System.out::println);
// 在转换时并没有执行类型检查因此支持直接转换
List<Integer> castList = new ArrayList<>(noGenericTypeList);
// 因此为了避免类型擦写导致的异常,因此需要使用包装类型工具类
// 当转换为checkedList时并不会进行类型校验
/**
* Wrapper(装饰器)模式的使用
* Collections.checked*接口弥补了 泛型运行时擦写的不足
* 强类型: 编译时泛型强制类型检查,运行时利用Collections.checked*强类型检查
*/
List<Integer> checkedList = Collections.checkedList(castList, Integer.TYPE);
// 会生成新的数据
System.out.println(checkedList == castList); noGenericTypeList = checkedList;
// 对于checkedList在执行添加时,会执行类型校验,因此会直接抛出错误
noGenericTypeList.add("B");
}

  

最新文章

  1. easyui相关script的配置
  2. jquery实现页面动态切换的方法--toggleClass(className)
  3. POJ1201 Intervals
  4. Android 网络流量监听开源项目-ConnectionClass源码分析
  5. C#(WinForm)上传图片保存到数据库和从数据库读取图片显示到窗体
  6. javascript版1024游戏源码
  7. shell脚本学习(二)
  8. Laravel 安装
  9. Android平台targetSdkVersion设置及动态权限
  10. linux 下安装arm-linux-gnueabi交叉编译器
  11. 关于asp.net mvc中的httpModules 与 httpHandler
  12. 创建.ignore文件
  13. [LeetCode&amp;Python] Problem 13. Roman to Integer
  14. MacBook小技巧
  15. stanford CS DB 课程 数据库系统实现
  16. unity3d Matrix4x4列为主序
  17. hadoop streaming怎么设置key
  18. config配置中心之自动刷新
  19. Swift2.0语言教程之闭包
  20. 十大基于Docker的开发工具

热门文章

  1. libview关于图片导入并显示
  2. 操作系统-I/O(5)I/O软件的层次结构
  3. A distributional code for value in dopamine-based reinforcement learning
  4. WS以及NW小世界网络的生成(MATLAB)
  5. 小白式DPDK搭建方法(附相关错误得处理方法)
  6. Java数据结构——双端队列
  7. 高并发&amp;性能优化(一)------总体介绍
  8. 高并发&amp;性能优化(二)------系统监控工具使用
  9. CCAI观后
  10. Node.js调试相关