JavaSE核心知识点02面向对象编程02-06(泛型)
🤟致敬读者
- 🟩感谢阅读🟦笑口常开🟪生日快乐⬛早点睡觉
📘博主相关
- 🟧博主信息🟨博客首页🟫专栏推荐🟥活动信息
文章目录
- JavaSE核心知识点02面向对象编程02-06(泛型)
- **一、为什么需要泛型?**
- **二、泛型的基本语法**
- **1. 定义泛型类/接口**
- **2. 使用泛型类**
- **三、泛型方法**
- **四、泛型通配符 `?`**
- **1. 无界通配符 `<?>`**
- **2. 上界通配符 `<? extends T>`**
- **3. 下界通配符 `<? super T>`**
- **PECS 原则**(Producer Extends, Consumer Super)
- **五、类型擦除(Type Erasure)**
- **六、泛型的限制与注意事项**
- **七、典型应用场景**
- **八、代码示例:自定义泛型栈**
- **九、总结**
📃文章前言
- 🔷文章均为学习工作中整理的笔记。
- 🔶如有错误请指正,共同学习进步。
JavaSE核心知识点02面向对象编程02-06(泛型)
泛型(Generics)是 Java 中非常重要的特性,它让代码更安全、更灵活。下面用通俗易懂的方式为你讲解,包含代码示例和核心概念。
一、为什么需要泛型?
问题:假设你要写一个可以存放任何类型数据的容器(比如一个盒子)。没有泛型时,代码可能这样写:
class Box {private Object data; // 用 Object 存储任意类型public void setData(Object data) {this.data = data;}public Object getData() {return data;}
}
缺陷:
- 取出数据时需要强制类型转换,容易出错。
- 无法限制放入的类型,可能混入不同类型的数据。
泛型的解决方案:让容器在定义时声明它能存储的数据类型。
Box<String> box = new Box<>(); // 只能存 String
box.setData("Hello"); // 正确
// box.setData(123); // 编译报错!
String data = box.getData(); // 无需强制转换
二、泛型的基本语法
1. 定义泛型类/接口
在类名后加<T>
,T
是类型参数(可以是任意标识符,如E
, K
, V
等)。
class Box<T> { // T 表示“某种类型”private T data;public void setData(T data) {this.data = data;}public T getData() {return data;}
}
2. 使用泛型类
创建对象时指定具体类型:
Box<String> stringBox = new Box<>(); // 存储 String
Box<Integer> intBox = new Box<>(); // 存储 Integer
三、泛型方法
即使类不是泛型,方法也可以独立声明泛型:
public class Utils {// 泛型方法:在返回类型前加 <T>public static <T> void printArray(T[] array) {for (T element : array) {System.out.println(element);}}
}// 使用
Integer[] intArray = {1, 2, 3};
Utils.printArray(intArray); // 自动推断类型为 Integer
四、泛型通配符 ?
用于处理未知类型,常见于方法参数或集合操作。
1. 无界通配符 <?>
表示接受任何类型:
public static void printList(List<?> list) {for (Object elem : list) {System.out.println(elem);}
}
2. 上界通配符 <? extends T>
表示类型是T
或其子类:
// 只能读取元素(因为元素是 Animal 或其子类)
public static void processAnimals(List<? extends Animal> animals) {for (Animal animal : animals) {animal.eat();}
}
3. 下界通配符 <? super T>
表示类型是T
或其父类:
// 可以写入元素(因为容器是 T 的父类)
public static void addNumbers(List<? super Integer> list) {list.add(123); // 允许添加 Integer
}
PECS 原则(Producer Extends, Consumer Super)
- 生产者(Producer):使用
<? extends T>
,只能读取。 - 消费者(Consumer):使用
<? super T>
,只能写入。
五、类型擦除(Type Erasure)
Java 泛型在编译后会被擦除为原始类型(如Object
),这是为了兼容旧版本 Java。例如:
List<String> list = new ArrayList<>();
// 编译后实际是:List list = new ArrayList();
影响:
- 运行时无法获取泛型的具体类型(如
T
的实际类型)。 - 不能创建泛型数组(如
new T[]
)。 - 泛型类型不能是基本类型(如
List<int>
错误,要用List<Integer>
)。
六、泛型的限制与注意事项
-
不能实例化类型参数:
// 错误!new T() 是非法的 T data = new T();
-
静态成员不能使用泛型类型:
class Box<T> {// 错误!静态变量不能是泛型private static T staticData; }
-
泛型与继承的关系:
List<String>
不是List<Object>
的子类。- 但
ArrayList<String>
是List<String>
的子类。
七、典型应用场景
- 集合框架(如
ArrayList<E>
、HashMap<K,V>
)。 - 工具类(如
Collections
中的泛型方法)。 - 自定义通用数据结构(如栈、队列、链表)。
八、代码示例:自定义泛型栈
class Stack<T> {private List<T> elements = new ArrayList<>();public void push(T element) {elements.add(element);}public T pop() {if (elements.isEmpty()) {throw new EmptyStackException();}return elements.remove(elements.size() - 1);}
}// 使用
Stack<Integer> stack = new Stack<>();
stack.push(1);
int num = stack.pop(); // 无需强制转换
九、总结
- 核心目的:提高代码的类型安全性和复用性。
- 关键语法:
<T>
定义泛型,?
处理未知类型。 - 注意事项:类型擦除、通配符的使用场景、PECS原则。
掌握泛型后,你将能写出更健壮、更灵活的 Java 代码!
📜文末寄语
- 🟠关注我,获取更多内容。
- 🟡技术动态、实战教程、问题解决方案等内容持续更新中。
- 🟢《全栈知识库》技术交流和分享社区,集结全栈各领域开发者,期待你的加入。
- 🔵加入开发者的《专属社群》,分享交流,技术之路不再孤独,一起变强。
- 🟣点击下方名片获取更多内容🍭🍭🍭👇