# 泛型简介
泛型是 Java SE 1.5
的新特性,泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。理解 Java
泛型最简单的方法是把它看成一种便捷语法,能节省你某些 Java
类型转换 (casting) 上的操作。
// 有泛型 | |
List<Apple> box = new ArrayList<Apple>(); | |
box.add(new Apple()); | |
Apple apple = box.get(0); | |
// 没有泛型 | |
Apple apple = (Apple)box.get(0); |
在以前的版本中使用泛型类型,需要在声明并赋值的时候,两侧都加上泛型类型。例如:
Map<String, String> myMap = new HashMap<String, String>(); |
很明显,在声明变量时已经指定了参数类型,在初始化对象时还需要再指定。在 Java 7
得到改进
Map<String, String> myMap = new HashMap<>(); // 注意后面的 "<>" |
编译器会根据变量声明时的泛型类型自动推断出实例化 HashMap
时的泛型类型。再次提醒一定要注意 new HashMap
后面的 “<>”,只有加上这个 “<>” 才表示是自动类型推断,否则就是非泛型类型的 HashMap
,并且在使用编译器编译源代码时会给出一个警告提示。
但是 Java SE 7
在创建泛型实例时的类型推断是有限制的:只有构造器的参数化类型在上下文中被显著的声明了,才可以使用类型推断,否则不行。例如:下面的例子在 java 7
无法正确编译。
List<String> list = new ArrayList<>(); | |
// 由于 addAll 期望获得 Collection<? extends String > 类型的参数,因此下面的语句无法通过 | |
list.addAll(new ArrayList<>()); |
addAll
的函数原型是
boolean addAll(Collection<? extends E> c); | |
// List 就是继承了 Collection |
# Java8 改进
java8
里面泛型的目标类型推断主要 2 个:
支持通过方法上下文推断泛型目标类型。
支持在方法调用链路当中,泛型类型推断传递到最后一个方法。
之前的 Java7
是构造器上下文。
class List<E> { | |
static <Z> List<Z> nil() { ... }; | |
static <Z> List<Z> cons(Z head, List<Z> tail) { ... }; | |
E head() { ... } | |
} |
我们可以这么使用
// 通过方法赋值的目标参数来自动推断泛型的类型 | |
List<String> l = List.nil(); | |
// 而不是显示的指定类型 | |
//List<String> l = List.<String>nil(); | |
// 通过前面方法参数类型推断泛型的类型 | |
List.cons(42, List.nil()); | |
// 而不是显示的指定类型 | |
//List.cons(42, List.<Integer>nil()); |
你记住 Java8
可以从方法上下文获取目标类型即可。之前的 list.addAll(new ArrayList<>());
, list
这个引用就指明了类型,所以 Java8
编译器可以推断出。
# 参考
Java 全栈知识体系:https://pdai.tech/md/java/java8/java8-type.html
注:网上关于 Java8 类型推断优化好多都一模一样,连吐槽都一样,一点都没有改过,由于它们都大多没写发布时间,我也不知道谁抄谁的。