对于泛型知识更为系统的学习
第一部分 泛型
- 对应学习视频:JavaSE强化教程泛型,由点到面的讲解了整个泛型体系
第1章 什么是泛型
- 背景:Object容易引发ClassCastException。
- 概念:JDK5引入,允许在编译时检测非法的数据结构,本质就是参数化类型,将数据类型指定为一个参数。
- 优点:类型安全,消除了强制类型转换。
第2章 泛型类、接口
1.2.1 泛型类
-
定义语法:
class 类名称 <泛型标识1, 泛型标识2, ···>{ private 泛型标识1 变量名1; private 泛型标识2 变量名2; ······ }
-
泛型标识:T, E, K, V
-
使用方法:
类名<具体数据类型> 对象名 = new 类名<具体数据类型>(); 类名<具体数据类型> 对象名 = new 类名<>(); //JDK1.7后,后面<>内的数据类型可省略
-
注意:泛型类不支持基本数据类型,只支持类类型;
不指定类型时,将按照Object类型操作;
同一泛型类数据类型不同时,本质上是同一类型。
-
泛型类派生子类:
-
子类也是泛型类,子类父类泛型类型要一致;
class ChildGeneric<T> extends Generic<T>
-
子类不是泛型类,父类要明确泛型的数据类型。
class ChildGeneric extends Generic<String>
-
1.2.2 泛型接口
-
定义语法
interface 接口名称 <泛型标识1, 泛型标识2, ···>{ 泛型标识 方法名(); ······ }
-
使用:
- 实现类不是泛型类,接口要明确数据类型;
- 实现类也是泛型类,泛型类型要与接口一致。
第3章 泛型方法
-
语法:
修饰符 <T, E, ...> 返回值类型 方法名(形参列表){ 方法体... } //泛型类中使用了泛型的成员方法不是泛型方法,必须要有修饰符和返回类型之间的泛型列表,在调用此方法时给定类型
-
可变参数语法:
public <E> void print(E... e){ for(E e1 : e){ System.out.println(e); } }
-
特点:
- 泛型方法独立于类而产生变化,相比于泛型类更加灵活;
- 静态方法要使用泛型必须采用泛型方法。
第4章 类型通配符
-
定义:使用 ? 代替具体的类型实参。
-
类型通配符上限:要求该泛型的类型只能是该实参类型或该实参类型的子类类型。
类/接口<? extends 实参类型>
注意:采用类型通配符上限的集合不可添加元素。
-
类型通配符下限:要求该泛型的类型只能是该实参类型或该实参类型的父类类型。
类/接口<? super 实参类型>
注意:采用类型通配符上限的集合可以添加元素(但不保证元素数据类型约束要求),遍历时全部用Object接收。
第5章 类型擦除
- 定义:泛型信息只存在于代码编译阶段,在进入JVM之前,与泛型相关的信息会被擦除掉
- 分类:
- 无限制类型擦除:擦除为Object;
- 有限制类型擦除:擦除为类型上限;
- 擦除方法中类型定义的参数:Object/上限;
- 桥接方法:保持接口和类的实现关系,将实现类中的方法重写并擦除为Object。
第6章 泛型与数组
-
创建:
-
可以声明带泛型的数组引用,但不能直接创建带泛型的数组对象;
ArrayList<String>[] listArr = new ArrayList[5];
-
通过 java.lang.reflect.Array 的 newInstance(Class, int) 创建T[]数组。
public class Fruit<T> { private T[] array; public Fruit(Class<T> clz, int length) { array = (T[]) Array.newInstance(clz, length); } public void put(int index, T item){ array[index]=item; } public T get(int index){ return array[index]; } public T[] getArray(){ return array; } }
-
-
尽量使用泛型集合而不是泛型数组。
第7章 泛型与反射
-
反射常用的泛型类:
- Class;
- Constructor。
-
示例:
Class<Person> personClass = Person.class; Constructor<Person> constructor = personClass.getConstructor(); Person person = constructor.newInstance();