当前位置: 首页 > news >正文

【数据结构前置知识】泛型

目录

1. 核心概念:什么是泛型?

2. 为什么需要泛型?(解决的问题)

问题示例:没有泛型的时代

泛型的解决方案

3. 泛型的基本语法和使用

3.1 泛型类

3.2 泛型接口

3.3 泛型方法

4. 泛型通配符:?, extends, super

4.1 无界通配符

4.2 上界通配符

4.3 下界通配符

5. 泛型与数据结构的关系(复习重点)

6. 类型擦除:泛型的实现机制


1. 核心概念:什么是泛型?

​泛型​​ 的本质是​​参数化类型​​。

简单来说:

  • 就像​​方法有参数​​一样(void print(String message)),​​类型也可以有参数​​。

  • 泛型允许我们在定义类、接口或方法时,使用一个​​类型占位符​​(如 <T>),等到实际使用时再指定具体的类型。

​核心思想​​:编写一次代码,适用于多种数据类型,同时保证​​类型安全​​。


2. 为什么需要泛型?(解决的问题)

在泛型出现之前,我们主要使用 Object类来实现"通用"的容器,但这会带来严重问题。

问题示例:没有泛型的时代
// 一个可以放任何东西的"盒子"类
class OldBox {private Object content;public void setContent(Object content) {this.content = content;}public Object getContent() {return content;}
}// 使用这个盒子
public static void main(String[] args) {OldBox stringBox = new OldBox();stringBox.setContent("Hello"); // 放入String// 问题1:需要强制类型转换,麻烦且容易出错String message = (String) stringBox.getContent();// 问题2:编译器无法进行类型检查,运行时才会报错!stringBox.setContent(123); // 误放入Integer,编译器不会警告String wrongMessage = (String) stringBox.getContent(); // 运行时ClassCastException!
}
泛型的解决方案
// 使用泛型的盒子类
class Box<T> { // T是类型参数private T content;public void setContent(T content) {this.content = content;}public T getContent() { // 返回类型就是T,不需要强制转换return content;}
}// 使用泛型盒子
public static void main(String[] args) {Box<String> stringBox = new Box<>(); // 创建时指定T为StringstringBox.setContent("Hello");// 优点1:不需要强制类型转换String message = stringBox.getContent();// 优点2:编译时类型检查,提前发现错误!// stringBox.setContent(123); // 编译错误!无法将Integer放入String的盒子Box<Integer> intBox = new Box<>(); // 可以创建Integer类型的盒子intBox.setContent(123);int number = intBox.getContent(); // 自动拆箱
}

​泛型的核心优势​​:

  1. ​类型安全​​:在编译期就能发现类型错误,而不是在运行时。

  2. ​消除强制类型转换​​:代码更简洁、更清晰。

  3. ​代码复用​​:一套代码可以用于多种数据类型。


3. 泛型的基本语法和使用

3.1 泛型类

在类名后面添加类型参数 <T>T是类型占位符(可以用任何大写字母,如 E, K, V等)。

// 定义一个泛型类
public class Container<T> {private T value;public Container(T value) {this.value = value;}public T getValue() {return value;}public void setValue(T value) {this.value = value;}
}// 使用
Container<String> stringContainer = new Container<>("Hello");
Container<Integer> intContainer = new Container<>(100);
3.2 泛型接口

接口也可以使用泛型。

// 泛型接口
public interface Repository<T> {void save(T entity);T findById(int id);
}// 实现泛型接口时指定具体类型
public class UserRepository implements Repository<User> {@Overridepublic void save(User user) { /* 实现 */ }@Overridepublic User findById(int id) { /* 实现 */ return null; }
}
3.3 泛型方法

即使类不是泛型类,方法也可以是泛型方法。

public class ArrayUtils {// 泛型方法:交换数组中两个元素的位置public static <T> void swap(T[] array, int i, int j) {T temp = array[i];array[i] = array[j];array[j] = temp;}// 使用泛型方法public static void main(String[] args) {String[] words = {"Hello", "World"};Integer[] numbers = {1, 2, 3};ArrayUtils.swap(words, 0, 1);    // T 被推断为 StringArrayUtils.swap(numbers, 0, 1);  // T 被推断为 Integer}
}

4. 泛型通配符:?, extends, super

这是泛型中比较难理解但非常重要的概念,用于增加API的灵活性。

4.1 无界通配符 <?>

表示"未知类型",当你只关心容器,不关心容器中元素的具体类型时使用。

// 打印任何List的内容,不关心元素类型
public static void printList(List<?> list) {for (Object elem : list) {System.out.print(elem + " ");}
}// 可以接受List<String>, List<Integer>等
printList(Arrays.asList("A", "B", "C"));
printList(Arrays.asList(1, 2, 3));
4.2 上界通配符 <? extends T>

表示"T或其子类型",用于​​生产者​​(主要从中读取数据)。

// 只能接受Number及其子类(Integer, Double等)的List
public static double sumOfList(List<? extends Number> list) {double sum = 0.0;for (Number num : list) { // 可以安全地当作Number读取sum += num.doubleValue();}return sum;
}List<Integer> intList = Arrays.asList(1, 2, 3);
List<Double> doubleList = Arrays.asList(1.1, 2.2, 3.3);System.out.println(sumOfList(intList));    // 正确
System.out.println(sumOfList(doubleList)); // 正确
4.3 下界通配符 <? super T>

表示"T或其父类型",用于​​消费者​​(主要向其中写入数据)。

// 只能接受Integer及其父类(Number, Object)的List
public static void addNumbers(List<? super Integer> list) {for (int i = 1; i <= 5; i++) {list.add(i); // 可以安全地添加Integer}
}List<Number> numberList = new ArrayList<>();
List<Object> objectList = new ArrayList<>();addNumbers(numberList); // 正确
addNumbers(objectList); // 正确

​PECS原则​​(Producer-Extends, Consumer-Super):

  • 如果参数是​​生产者​​(提供数据),使用 <? extends T>

  • 如果参数是​​消费者​​(消耗数据),使用 <? super T>


5. 泛型与数据结构的关系(复习重点)

​集合框架就是泛型最典型、最重要的应用!​

// List<E> 接口是泛型接口
List<String> stringList = new ArrayList<>(); // E 被指定为 String
List<Integer> intList = new ArrayList<>();   // E 被指定为 Integer// Map<K, V> 也是泛型接口
Map<String, Integer> ageMap = new HashMap<>(); // K=String, V=Integer// 没有泛型的"远古时代"写法(不要这样写!)
List oldList = new ArrayList(); // 默认是List<Object>
oldList.add("hello");
oldList.add(123); // 编译器不报错,但...
String str = (String) oldList.get(1); // 运行时ClassCastException!

​正是因为泛型,集合框架才能:​

  1. ​保证类型安全​​:ArrayList<String>只能存放String。

  2. ​避免强制转换​​:从 list.get(0)直接得到String,而不是Object。

  3. ​提供更好的API​​:IDE能提供准确的代码提示和类型检查。


6. 类型擦除:泛型的实现机制

Java的泛型是​​编译期概念​​,在编译后,泛型信息会被擦除,这个过程叫做​​类型擦除​​。

// 源代码
List<String> stringList = new ArrayList<>();
List<Integer> intList = new ArrayList<>();// 编译后(概念上),泛型信息被擦除,都变成原始类型List
List stringList = new ArrayList();
List intList = new ArrayList();

​类型擦除的影响​​:

  • 运行时无法获取泛型的具体类型信息(如 T.class是不允许的)

  • 不能创建泛型数组(如 new T[]

  • 是Java为了向后兼容而采取的设计

了解泛型擦除详情,请看这篇帖子 ——> 泛型擦除

http://www.dtcms.com/a/403921.html

相关文章:

  • Flink SourceOperator和WaterMark
  • 容器化 Djiango 应用程序
  • 营销网站建设企划案例网站建设业务越做越累
  • Java EE、Java SE 和 Spring Boot
  • 两学一做专题网站wordpress 用户密码的加密算法
  • 手写数据结构-- avl树
  • MySQL-事务日志
  • SpringBoot旅游管理系统
  • 永州市城乡建设规划局网站湖南大型网站建设公司
  • 买东西网站有哪些汽车设计公司排名前十强
  • IT 疑难杂症诊疗室:破解常见故障的实战指南​
  • 集团网站建设详细策划广告设计与制作模板
  • OSError: [WinError 182] 操作系统无法运行 %1。 解决办法
  • 部门网站建设的工作领导小组局域网建设简单的影视网站
  • 嵌入式学习(45)-基于STM32F407Hal库的Modbus Slave从机程序
  • 【字符串算法集合】KMP EXKMP Manacher Trie 树 AC 自动机
  • 网站是哪家公司开发的中山网站建设文化价位
  • 织梦网站如何备份教程企业网站建设公司网络
  • 杭州的网站建设公司4s店网站建设方案
  • 如果在自己电脑上运行,没有问题。但是移植到工控机,有问题
  • 网站建设计划方案中国著名的个人网站
  • 漫谈<爬虫与反爬的斗争>之反爬技术全景综述
  • @WebFilter 过滤器的执行顺序
  • 唐山建站方案七台河新闻综合频道直播
  • webpack library
  • 网站如何做背景音乐苏州集团网站建设
  • 建设工程招聘信息网站微信pc版
  • windows系统怎么做ppt下载网站永康外贸网站建设
  • 人工设计图像特征
  • 网站抓取qqwordpress 菜单 导航