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

Java基础知识(十二)

一、泛型的核心概念

  • 定义:泛型是 Java 5 引入的特性,允许在定义类、接口、方法时使用类型参数(Type Parameter),在使用时指定具体类型,实现 "参数化类型" 的效果。
  • 本质:通过类型参数化,将类型检查从运行时提前到编译时,减少类型转换,提高代码复用性和安全性。
  • 作用
    • 避免频繁的类型转换(如 (String) list.get(0)
    • 编译时检查类型安全性,防止 ClassCastException
    • 编写通用代码,实现 "一次编写,多处使用"

二、泛型的基本语法

1. 泛型类

在类名后使用 <类型参数> 定义,类型参数通常用单个大写字母表示(如 T、E、K、V)。

// 定义泛型类:容器类,可存储任意类型的数据
public class Box<T> {private T content; // 使用类型参数 T 定义成员变量// 使用类型参数 T 作为方法参数和返回值public void setContent(T content) {this.content = content;}public T getContent() {return content;}
}// 使用泛型类:指定具体类型
public class GenericClassDemo {public static void main(String[] args) {// 1. 创建存储 String 类型的 BoxBox<String> stringBox = new Box<>();stringBox.setContent("Hello Generics");String str = stringBox.getContent(); // 无需类型转换// 2. 创建存储 Integer 类型的 BoxBox<Integer> intBox = new Box<>();intBox.setContent(100);Integer num = intBox.getContent();}
}

2. 泛型接口

与泛型类类似,在接口名后添加类型参数。

// 定义泛型接口:生成器接口
public interface Generator<T> {T generate(); // 方法返回值为类型参数 T
}// 实现泛型接口:指定具体类型(String)
public class StringGenerator implements Generator<String> {@Overridepublic String generate() {return "Generated string";}
}// 实现泛型接口:保留类型参数(泛型实现类)
public class NumberGenerator<T extends Number> implements Generator<T> {private T number;public NumberGenerator(T number) {this.number = number;}@Overridepublic T generate() {return number;}
}

3. 泛型方法

在方法返回值前声明 <类型参数>,可在普通类或泛型类中定义。

public class GenericMethodDemo {// 泛型方法:打印任意类型的数组public static <T> void printArray(T[] array) {for (T element : array) {System.out.print(element + " ");}System.out.println();}public static void main(String[] args) {// 调用泛型方法:自动推断类型Integer[] intArray = {1, 2, 3, 4};printArray(intArray); // 输出:1 2 3 4 String[] strArray = {"A", "B", "C"};printArray(strArray); // 输出:A B C }
}

三、类型通配符与边界

1. 无界通配符(?)

表示任意类型,用于不确定具体类型的场景。

public class WildcardDemo {// 打印任意类型的 Box 内容public static void printBoxContent(Box<?> box) {System.out.println(box.getContent());}public static void main(String[] args) {Box<String> stringBox = new Box<>();stringBox.setContent("Test");printBoxContent(stringBox); // 输出:TestBox<Integer> intBox = new Box<>();intBox.setContent(123);printBoxContent(intBox); // 输出:123}
}

2. 上界通配符(? extends T)

表示类型必须是 T 或 T 的子类(限制上限)。

// 计算数字列表的总和(只能处理 Number 及其子类)
public static double sumOfList(List<? extends Number> list) {double sum = 0.0;for (Number num : list) {sum += num.doubleValue();}return sum;
}// 使用示例
List<Integer> intList = Arrays.asList(1, 2, 3);
List<Double> doubleList = Arrays.asList(1.5, 2.5, 3.5);
System.out.println(sumOfList(intList));    // 输出:6.0
System.out.println(sumOfList(doubleList)); // 输出:7.5

3. 下界通配符(? super T)

表示类型必须是 T 或 T 的父类(限制下限)。

// 向列表添加整数及其父类类型(如 Number、Object)
public static void addIntegers(List<? super Integer> list) {list.add(1);list.add(2);list.add(3);
}// 使用示例
List<Integer> intList = new ArrayList<>();
List<Number> numList = new ArrayList<>();
List<Object> objList = new ArrayList<>();addIntegers(intList);  // 合法
addIntegers(numList);  // 合法
addIntegers(objList);  // 合法

四、泛型的限制与注意事项

  1. 不能使用基本类型实例化泛型

    Box<int> intBox = new Box<>(); // 错误!不能使用基本类型
    Box<Integer> intBox = new Box<>(); // 正确,使用包装类
    
  2. 泛型类型参数不能用于静态成员

    public class StaticGeneric<T> {private static T value; // 错误!静态成员不能使用泛型参数
    }
    
  3. 不能实例化泛型类型的对象

    public class InstantiateGeneric<T> {public InstantiateGeneric() {T obj = new T(); // 错误!不能直接实例化泛型类型}
    }
    
  4. 泛型数组创建限制

    T[] array = new T[10]; // 错误!不能直接创建泛型数组
    T[] array = (T[]) new Object[10]; // 可以通过类型转换实现
    
  5. 泛型擦除(Type Erasure)

    • 编译后泛型信息会被擦除,替换为其边界类型(无边界则替换为 Object)
    • 运行时无法获取泛型的具体类型信息

    public class ErasureDemo {public static void main(String[] args) {Box<String> stringBox = new Box<>();Box<Integer> intBox = new Box<>();// 泛型擦除后,两者类型相同System.out.println(stringBox.getClass() == intBox.getClass()); // 输出:true}
    }
    
  6. 不能捕获泛型异常

    public class GenericException<T extends Exception> {public void method() {try {// 业务逻辑} catch (T e) { // 错误!不能捕获泛型异常// 处理异常}}
    }
    

五、泛型的典型应用场景

  1. 集合框架:Java 集合大量使用泛型(如 List<T>Map<K,V>

    List<String> strList = new ArrayList<>();
    strList.add("Java");
    String s = strList.get(0); // 无需类型转换
    
  2. 通用工具类:创建可处理多种类型的工具方法

    // 通用的对象复制工具
    public class CopyUtil {public static <T> T copy(T source) {// 实现对象复制逻辑return null;}
    }
    
  3. 自定义容器:实现通用的数据结构(如链表、栈、队列)

    // 泛型链表节点
    class Node<T> {T data;Node<T> next;Node(T data) {this.data = data;}
    }
    

  1. 类型参数化
    允许在定义类、接口、方法时使用抽象的类型参数(如 <T><K,V>),在使用时再指定具体类型。
    例如:List<String> 中 String 是对泛型参数 T 的具体实例化,使集合只能存储字符串类型。

  2. 编译时类型安全
    编译器会根据泛型参数检查数据类型,避免将错误类型的数据存入容器,将运行时可能发生的 ClassCastException 提前到编译阶段暴露。
    例如:List<Integer> 中添加字符串会直接编译报错,而不是在运行时崩溃。

  3. 减少类型转换
    使用泛型后,从容器中获取元素时无需手动强制类型转换,编译器会自动根据泛型参数推断类型。
    对比:

    • 非泛型:String s = (String) list.get(0);(需强制转换)
    • 泛型:String s = list.get(0);(自动类型匹配)
  4. 代码复用性
    一套泛型代码可适配多种数据类型,无需为每种类型重复编写逻辑。
    例如:ArrayList<T> 可通过指定不同类型参数(ArrayList<Integer>ArrayList<String>)存储任意数据,而底层实现代码一致。

  5. 支持类型通配与边界
    通过通配符(?)和边界(extendssuper)实现灵活的类型限制:

    • 上界通配符 ? extends T:限制类型为 T 或其子类(如 List<? extends Number> 可接收 List<Integer>List<Double>)。
    • 下界通配符 ? super T:限制类型为 T 或其父类(如 List<? super Integer> 可接收 List<Integer>List<Number>)。
  6. 泛型擦除(Type Erasure)
    编译后泛型信息会被擦除,替换为其边界类型(无边界则为 Object),因此运行时无法获取泛型的具体类型。
    例如:List<String> 和 List<Integer> 在运行时的类型均为 List

  7. 泛型独立化
    不同泛型参数的实例被视为同一类型的不同参数化版本,不具备继承关系。
    例如:List<String> 不是 List<Object> 的子类,即使 String 继承 Object

http://www.xdnf.cn/news/19283.html

相关文章:

  • 8.31【Q】CXL-DMSim:
  • vue3+vite+ts 发布npm 组件包
  • Deep Think with Confidence:llm如何进行高效率COT推理优化
  • 第24章学习笔记|用正则表达式解析文本文件(PowerShell 实战)
  • zkML-JOLT——更快的ZK隐私机器学习:Sumcheck +Lookup
  • Pytest 插件介绍和开发
  • leetcode 260 只出现一次的数字III
  • COLA:大型语言模型高效微调的革命性框架
  • 免费电脑文件夹加密软件
  • 基于Adaboost集成学习与SHAP可解释性分析的分类预测
  • 【K8s】整体认识K8s之存储--volume
  • 在win服务器部署vue+springboot + Maven前端后端流程详解,含ip端口讲解
  • Transformer架构三大核心:位置编码(PE)、前馈网络(FFN)和多头注意力(MHA)。
  • 学习Python中Selenium模块的基本用法(12:操作Cookie)
  • TFS-2005《A Possibilistic Fuzzy c-Means Clustering Algorithm》
  • 使用 Python 自动化检查矢量面数据的拓扑错误(含导出/删除选项)
  • 算法题(196):最大异或对
  • 特殊符号在Html中的代码及常用标签格式的记录
  • Qt组件布局的经验
  • 线程池、锁策略
  • 机器视觉opencv教程(四):图像颜色识别与颜色替换
  • Linux中的ss命令
  • kotlin - 2个Activity实现平行视图,使用SplitPairFilter
  • 网络流量分析——使用Wireshark进行分析
  • Shell脚本编程——变量用法详解
  • Ruoyi-vue-plus-5.x第二篇MyBatis-Plus数据持久层技术:2.2 分页与性能优化
  • DAY17-新世纪DL(DeepLearning/深度学习)战士:Q(机器学习策略)2
  • AI 应用 图文 解说 (二) -- 百度智能云 ASR LIM TTS 语音AI助手源码
  • 自定义AXI_PWM_v1.0——ZYNQ学习笔记15
  • Spring Task快速上手