为什么需要范型

  • 刚开始是没有范型的,Java5才引入,Go至今没有引入
  • 没有范型时如何实现类型安全?
    • List没有类型
    • 答案是没有办法保证类型安全 ```java // 以List为例,没有范型时Java没办法保证类型安全 List list = new ArrayList(); list.add(new Object()); list.add(1); list.add(“aaa”);

// 只能自己在代码层面去一个个封装限制(可以用decorator) // 这样做太麻烦了,因此,引入了范型 class StringList { List list = new ArrayList(); void add(String e) {} // … }

class StringObjectMap { // … } ```

有了范型之后

  • 可以省时省力地写出类型安全代码
    • List
    • Map
    • Map>
  • 有范型之后,我们还支持无范型的“原始类型”的容器吗?
    • 为了向后兼容,还是支持,所以旧版本的代码可以跑在最新的JDK
  • 向后兼容(支持无范型)的两种选择
    • 类型擦除(type erasure): Java的选择(也是有人说Java是假范型的原因)
    • 搞一套全新的API:C#的选择(比如:GenericArrayList)
  • 历史
    • Java的容器在1.2时就分裂过一次,Vector,HashTable等被废除,由ArrayList、HashMap等替代
    • 但是JDK中并没有删除它们

Type Erasure带来的问题

  • Java的范型是假范型,是编译期的范型
    • 运行期不保留范型信息(范型只是编译器在用)
  • List并不是List的子类型
    • 对比String/Object、String[]/Object[],范型不支持的原因就是类型擦除
  • 编译器的警告
    • 使用限定符List<?>
    • 可以通过利用范型擦除来绕过编译器检查
  • 范型的限定符

    • 范型方法是如何工作的
    • 范型方法的绑定
      • 按照参数绑定
      • 按照返回值自动绑定
      • ?extends要求范型是某种类型及其子类型
      • ?super求范型是某种类型及其父类型
    • 最难的绑定
      • Collectors的一系列范型化方法