Loading... # 1. 基本概念 什么是泛型?泛型用来做什么? 在有泛型类之前,程序员必须使用Object编写适用于多种类型的代码,这不仅繁琐,且很不安全(无类型推断来做编译前检测)。 泛型程序设计意味着编写的代码可以对多种不同类型的对象重用。例如,你不希望为收集一组String和File对象分别写两个类。实际上我们使用的ArrayList类就可完成这个工作。它就是一个泛型类。 ---------- # 2. 泛型类 泛型类(generic class)就是有一个或多个类型变量的类。泛型类相当于普通类的工厂。 简单示例: ```java public class Pair<T> { private T first; private T second; public Pair(T first, T second) { this.first = first; this.second = second; } SetterAndGetter..... } ``` ---------- # 3. 泛型方法 ## 简单例子 注意:类型变量T,放在修饰符(public static等)后面,返回类型前面,并用`<>`包裹。 实例1: ```java public class ArrayAlg { /** * @param a 为 varargs 是一个 T[] 数组 */ public static <T> T getMiddle(T... a){ return a[a.length / 2]; } public static void main(String[] args) { String middle = ArrayAlg.getMiddle("join", "Q.", "Public"); System.out.println(middle); } /* * 输出 Q. */ } ``` ## 泛型变量限定 实例2: 类型变量的限定。对类型变量加以约束。 ```java public class ArrayAlg { /** * 返回一对值,一个最大值,一个最小值 * * @param a 参数 */ public static <T extends Comparable> Pair<T> minMax(T[] a) { if (a == null || a.length == 0) { return null; } T min = a[0]; T max = a[0]; for (T t : a) { if (min.compareTo(t) > 0) { min = t; } if (max.compareTo(t) < 0) { max = t; } } return new Pair<>(min, max); } public static void main(String[] args) { LocalDate[] birthDays = { LocalDate.of(2906, 12, 9), LocalDate.of(1815, 12, 9), LocalDate.of(1903, 12, 9), LocalDate.of(1966, 12, 9), LocalDate.of(1906, 12, 9), LocalDate.of(1222, 12, 9) }; Pair<LocalDate> mm = ArrayAlg.minMax(birthDays); System.out.println("min = " + mm.getFirst()); System.out.println("max = " + mm.getSecond()); } } ``` 输出: ``` min = 1222-12-09 max = 2906-12-09 ``` ---------- # 4. 泛型代码及虚拟机 ## 类型擦除 无论何时定义一个泛型类型,都会自动提供一个相应的`原始类型(raw type)`。这个原始类型的名字就是去掉类型参数后的泛型类型名。类型变量会被`擦除`,并将其替换其限定类型(例如:Pair< T extends xxx > )。特别的,对于无限定的变量(例如:Pair<T>)则替换为Object。 类型擦除后的结果后,结果就是一个普通的类,就好像Java语言中引入泛型之前实现的类一样。 ## 转换泛型表达式 调用一个泛型方法调用时,如果擦除了返回类型(如将 T 擦除为 Object),编译器会插入强制类型转换。 ```java Pair<Employee> buddies = .......; Employee buddy = buddies.getFirst(); ``` * 对于原始方法`Pair.getFirst`进行调用 * 将类型擦除后返回的`Object`强制转换为`Employee`类型 ## 小总结 对于Java泛型的转换,需要记住以下几个事实: * 虚拟机中没有泛型,只有普通的类和方法。 * 所有的类型参数都会替换为他们的限定类型。 * 为保持类型安全性,必要时会插入强制类型转换。 ---------- # 5. 泛型类型的继承规则(重要) ![泛型类型的继承规则.png][1] 简而言之,不管类型S和类型T有什么关系,`List<S>` 和 `List<T>` **不会有任何关系**! ---------- # 6. 通配符类型(重要) 如同上一节介绍的一样,严格的泛型类型系统的使用是很复杂的,由此Java设计者引入了一个新的概念,通配符。在通配符类型中,允许类型参数发生变化。 > 注意:`?`与`T`的使用位置不完全相同!用途更是不同!`T`用于定义泛型。`?`用于方便泛型使用。而且`?`仅用于方法参数处。 ## 通配符的子类限定 例如: 通配符类型 `List< ? extends Person>` ,表示任何泛型List类型,他的类型类型参数是Person的子类。如`List<Student>`、`List<Teacher>`。但不能是`List<String>`。 ![通配符子类限定.png][2] ## 通配符的超类型限定 这是通配符附加的能力,也是相较于普通类型变量限定(T extends xxx)强大的地方。 例如: `List<? super Student>` 、`List< ? super T>` 。 ![通配符超类限定.png][3] ## 无限定通配符 无限定的通配符:`List<?>`看起来和原始的不加限定的`List<T>`没什么区别。 `List<?>`是一个脆弱的类型。它对于很多简单的操作非常有用。如果方法中并没有用到实际的类型,那么使用?在一定程度可以简化代码。 [1]: https://assets.fangshirui.cn/typecho/uploads/2020/11/2525495396.png [2]: https://assets.fangshirui.cn/typecho/uploads/2020/11/621595310.png [3]: https://assets.fangshirui.cn/typecho/uploads/2020/11/4053111827.png 最后修改:2020 年 12 月 10 日 08 : 20 PM © 允许规范转载