文章目录
🚀 一、泛型类的定义
🌟 1.1 语法
class className<T1,T2,T3,...>{
// 这里可以使用包装类型参数
}
class 泛型类名称<类型参数列表> extends 继承类{
}
class className<T> extends Parent<T>{
}
< T > 是占位符,表示当前类为泛型类。
泛型形参一般使用一个大写字母表示,常用名称:
- E : Element
- K : Key
- V : Value
- N : Number
- T : Type
🌟 1.2 泛型类的使用
泛型类<类型实参> 变量名 ; // 定义一个泛型类引用
new 泛型类<类型实参>(方法实参); // 实例化一个泛型类对象
MyArrayList<Integer> list = new MyArrayList<Integer>();
🚀 二、 泛型类的类型边界
在定义泛型类时,有时需要对传入的类型变量做一定的约束,可以通过类型边界约束。
// Number : 类型边界
// 只接受 Number 或其子类作为类型实参
class MyArrayLsit<E extends Number>{
}
没有指定类型边界时,默认边界为 Object 。
🌟 2.2 复杂一点的示例
public class BSTree<K extends Comparable<K>, V>{
...
}
// 传入的 K 必须是实现 Comparable 的,并且可以和另一个 K 类型做比较的。
🚀 三、 类型擦除
泛型是作用在编译期间的一种机制,实际上运行期间是没有这么多类的,那么运行期间是什么类型呢? 这里就是类型擦除在作用。
class MyArrayList<E>{
// 被擦除为 Object
}
class MyArrayList<E extends Comparable<E>>{
// 被擦除为 Comparable
}
类型擦除主要看其类型边界而定。
🚀 四、 通配符
? 在泛型中的使用,即为通配符。
通配符是用来解决泛型无法协变的问题的。协变指的就是如果 Student 是 Person 的子类,那么 List< Studnet > 也应该是 List< Person > 的子类,但是泛型并不支持这样的父子关系。
// 通配符的使用让该方法可以传入任意类型的 MyArrayList
class printAll(MyArrayList<?> list){
...
}
🌟 4.1 通配符上界
语法格式如下:
< ? extends 上界>
// 可以传入Number及其子类的任意类型
class static void printAll(MyArrayList<? extends Number> list){
...
}
❗ 注意:
需要区分 泛型使用中的通配符上界和泛型定义中的类型上界。
🌟 4.2 通配符下界
语法格式如下:
< ? extends 下界>
// 可以传入实参是 Integer 父类的任意类型
public static void printfAll(ArrayList<? super Integer> list){
...
}
- 传入数据时,可以传入是 Integer 子类的数据。
- 读取数据时,只能使用 Object 接收,因为发生了类型擦除。
🚀 五、 泛型中的父子关系
泛型中的父子关系要依靠通配符来确定。
public class MyArrayList<T>{...}
// MyArrayList<Object> 不是 MyArrayList<Number> 的父类型
// MyArrayList<Number> 不是 MyArrayList<Integer> 的父类型
// MyArrayList< ? > 是 MyArrayList<? extends Number> 的父类型
// MyArrayList<? extends Number> 是 MyArrayList< Integer > 的父类型
🚀 六、 泛型方法
定义语法
方法限定符 <类型形参列表> 返回值类型 方法名(形参列表){...}
示例
public static <E> void swap(E[] arr,int i,int j){
E t = arr[i];
arr[i] = arr[j];
arr[j] = t;
}
泛型的限制
❗ 注意:
- 泛型类型参数不支持基本数据类型。
- 无法实例化泛型类型对象。
- 无法使用泛型类型声明静态属性。
- 无法使用 instanceof 判断泛型类型。
- 无法创建泛型数组。
- 异常不支持泛型。
- 泛型类型不是形参的一部分,无法重载。
191

被折叠的 条评论
为什么被折叠?



