Pixiv - KiraraShss
1470 字
7 分钟
泛型
泛型
一、 泛型的引入与好处
1.1 传统方法的问题
在集合中,使用传统方法(不使用泛型)存在两个主要问题:
- 类型不安全:不能对加入到集合中的数据类型进行约束,可以添加任意类型的对象。
- 效率低:遍历时,需要进行频繁的类型转换(Object -> 具体类型),数据量大时影响效率。
1.2 泛型的好处
使用泛型可以解决上述问题:
-
类型安全:在编译时检查添加元素的类型,不符合则报错,提高了安全性。
-
提高效率:减少了遍历时不必要的类型转换次数。
- 不使用泛型:Dog -> Object (存入) -> Dog (取出,需强转)
- 使用泛型:Dog -> Dog (存入) -> Dog (取出,无需强转)
-
消除警告:代码更加简洁、健壮,不再有编译警告。
二、 泛型介绍
2.1 基本概念
- 泛型:又称参数化类型,是 JDK 5.0 引入的新特性。
- 核心思想:在类声明或实例化时,通过一个标识符来指定操作的数据类型。
- 作用:可以在类声明时,用一个标识符表示类中某个属性的类型、某个方法的返回值类型或参数类型。
- 优点:保证如果程序在编译时没有发出警告,运行时就不会产生 ClassCastException 异常。
三、 泛型语法与使用
3.1 泛型的声明与实例化
- 声明:在类名或接口名后使用尖括号 <> 定义泛型标识符,如 class Person<E>, interface List<T>。
- 实例化:在创建对象时,在尖括号 <> 中指定具体的类型。
// 声明一个泛型类class Person<E> { ... }// 实例化,指定 E 为 String 类型Person<String> person = new Person<String>("韩顺平教育");3.2 泛型使用的注意事项和细节
- 类型限制:泛型标识符 T, E 等只能是引用类型,不能是基本数据类型。
List<Integer> list1 = new ArrayList<Integer>(); // OK// List<int> list2 = new ArrayList<int>(); // 错误- 继承关系:在给泛型指定具体类型后,可以传入该类型或其子类类型。
- 使用形式:
// 完整写法ArrayList<Integer> list1 = new ArrayList<Integer>();// 简化写法(类型推断),推荐使用ArrayList<Integer> list2 = new ArrayList<>();// 未指定泛型,默认为 ObjectArrayList list3 = new ArrayList(); // 等价于 ArrayList<Object> list3 = ...四、 自定义泛型
4.1 自定义泛型类
- 基本语法:class 类名<T, R…> { … }

-
注意细节:
- 普通成员(属性、方法)可以使用泛型。
- 不能初始化使用泛型的数组(因为 new 时无法确定 T 的具体类型)。
- 静态成员(属性、方法)中不能使用类的泛型(因为静态成员在类加载时初始化,而泛型类型在创建对象时才确定)。
- 泛型类的类型,是在创建对象时确定的。
- 如果在创建对象时没有指定类型,则默认为 Object。
4.2 自定义泛型接口
-
基本语法:interface 接口名<T, R…> { … }
-
注意细节:
- 接口中,静态成员也不能使用泛型(同泛型类)。
- 泛型接口的类型,在继承接口或实现接口时确定。
- 没有指定类型,默认为 Object。
4.3 自定义泛型方法
-
基本语法:修饰符 <T, R…> 返回类型 方法名(参数列表) { … }
-
注意细节:
- 泛型方法可以定义在普通类中,也可以定义在泛型类中。
- 当泛型方法被调用时,类型会确定。
- public void eat(E e) {} 这样的方法,其泛型 E 依赖于类定义的泛型,不是泛型方法。
- public <T> void fly(T t) {} 这样的方法,其泛型 T 独立于类,是泛型方法。
五、 泛型的继承和通配符
5.1 泛型没有继承性
- 虽然 String 是 Object 的子类,但 List<String> 并不是 List<Object> 的子类。它们是并列关系,没有继承关系。
5.2 泛型通配符
为了表示泛型之间的某种关系,引入了通配符 ?。
-
<?>:无界通配符
- 表示可以接受任意的泛型类型。
- List<?> 是 List<String>, List<Object> 等各种泛型 List 的父类。
- 注意:不能向 List<?> 中添加除 null 以外的任何元素(因为类型不确定),但可以读取,读取出的类型是 Object。
-
<? extends A>:上界通配符
- 表示可以接受 A 类以及 A 类的子类(不限于直接子类)。
- 规定了泛型的上限。
- 同样,不能向 List<? extends A> 中添加除 null 以外的任何元素(因为无法确定具体是哪个子类),但可以读取,读取出的类型是 A。
-
<? super A>:下界通配符
- 表示可以接受 A 类以及 A 类的父类(不限于直接父类)。
- 规定了泛型的下限。
- 可以向 List<? super A> 中添加 A 及其子类对象(因为父类引用可以指向子类对象)。
- 读取时,返回的类型是 Object。
六、 JUnit 单元测试(补充)
6.1 为什么需要 JUnit
- 传统测试需要将代码写入 main 方法,测试多个功能时需要来回注销、切换,非常麻烦。
- JUnit 可以直接运行一个方法进行测试,并给出相关信息,方便快捷。
6.2 基本介绍
- JUnit 是一个 Java 语言的单元测试框架。
- 多数 Java 开发环境(如 IDEA)都已集成 JUnit 作为单元测试工具。
6.3 使用步骤(简述)
- 在需要测试的类中,导入 JUnit 相关包(通常由 IDE 自动完成)。
- 在需要测试的方法上添加 @Test 注解。
- 在方法体内编写测试代码。
- 右键点击方法名或类名,选择 Run ‘方法名()’ 或 Run ‘类名’ 执行测试。
支持与分享
如果这篇文章对你有帮助,欢迎分享给更多人或赞助支持!