Java 泛型快速学习指南(面向接口扫描场景)

Java 泛型快速学习指南(面向接口扫描场景)

目标:让你能读懂 / 看懂被扫描 Java 代码里的泛型,理解扫描工具在「DTO 展开、包装类解包」时到底在干什么。

不需要背语法细节,重点是建立直观理解。
摘要 :本文用最短篇幅讲清 Java 泛型的核心概念------泛型是给容器/方法提前声明的占位类型,编译期定死类型、免强转。内容覆盖泛型类、泛型方法、多类型参数、泛型嵌套(Result<List<OrderDTO>> 这类"套娃")、通配符 ?、数组/List 两行式输出口径,以及泛型擦除为何导致运行时拿不到 T。文末附最小速查表,面向接口扫描场景,帮你建立直观理解、读懂被扫描代码里的泛型。


一、泛型是什么(一句话)

泛型 = 给"容器/方法"提前声明一个"占位类型 T",使用时再填上具体类型。

没有泛型时,集合里放的是 Object,取出来要强转,容易出错:

java 复制代码
List list = new ArrayList();
list.add("abc");
String s = (String) list.get(0); // 必须强转,类型不安全

有了泛型,类型在编译期就定死,取出来直接用:

java 复制代码
List<String> list = new ArrayList<>();
list.add("abc");
String s = list.get(0); // 不需要强转,编译器保证里面一定是 String

核心好处:编译期类型检查 + 免强转。


二、最基本的几种写法

1. 类上的泛型(泛型类)

java 复制代码
class Box<T> {        // T 是类型占位符,名字随便起(常用 T/E/K/V)
    private T value;
    public T getValue() { return value; }
    public void setValue(T value) { this.value = value; }
}
// 使用时:
Box<String> b = new Box<>();
b.setValue("你好");    // 这里 T 被"填"成了 String

2. 方法上的泛型(泛型方法)

java 复制代码
public <T> T getFirst(List<T> list) {
    return list.get(0);
}
// 调用时 T 由实参自动推断
String s = getFirst(Arrays.asList("a", "b"));

3. 多个类型参数

java 复制代码
class Pair<K, V> {
    private K key;
    private V value;
}
// 你项目里常见:Map<String, OrderDTO> 就是 K=String, V=OrderDTO

三、你最可能遇到的"套娃"类型

1. 泛型嵌套(重点)

java 复制代码
List<OrderDTO>            // 元素类型是 OrderDTO
Result<List<OrderDTO>>    // Result 包裹 List,List 包裹 OrderDTO
Page<OrderVO>             // 分页对象,里面是 OrderVO 列表

理解口诀:从外往里一层层剥。扫描工具也正是这么做的:

  • 看到 Result<T> → 先把 Result 这个"容器"当一行;
  • 再把 T(实参)树挂到它下面继续展开。

2. 通配符 ?(你大概只需知道它存在)

java 复制代码
List<?>          // 任意类型的 List
List<? extends Number>  // 元素类型是 Number 或其子类(上界)
List<? super Integer>   // 元素类型是 Integer 或其父类(下界)

实际扫描里一般不用深究,工具多半按"保留容器行 + 不强行展开"处理。

3. 数组 / List 两行式(对应你工具的输出口径)

源码:

java 复制代码
private List<OrderItemDTO> items;

输出报文里会变成两行:

  • 数组行:items type=List<OrderItemDTO>
  • 元素行:挂在 items 下,name=OrderItemDTO,继续展开其字段

四、泛型擦除(为什么运行时拿不到 T)

Java 的泛型是编译期 的:编译完之后,List<String>List<Integer> 在 JVM 里都是同一个 List(类型信息被"擦掉")。

java 复制代码
// 编译后等价于:
List list = new ArrayList();

这解释了:

  • 为什么不能 new T()、不能 new List<T>()(运行时不知道 T 是谁);
  • 为什么扫描工具必须靠读源码/字节码里的声明来还原泛型,而不能在运行时探测。

五、最小速查表

写法 读法
T / E / K / V 类型占位符(Type/Element/Key/Value)
List<String> 装 String 的列表
Map<String, OrderDTO> key=String, value=OrderDTO 的映射
Result<T> 泛型包装容器,T 是真正的业务数据
Result<List<X>> 包装容器里套了一个 X 列表
? extends X X 或其子类
? super X X 或其父类

想深入再补:泛型边界 <T extends Comparable<T>>、泛型构造器、桥接方法。日常接口扫描用不到,遇到再说。

相关推荐
我是大猴子1 小时前
redis执行get等命令时底层操作
java
叶总没有会1 小时前
微服务--分布式基础
java·spring·spring cloud·微服务
鹿角片ljp1 小时前
Prompt Cache、Token 成本与 Plan Compiler 的工程设计
java·python·算法
Wang's Blog2 小时前
Java 接入Redis: 五大数据类型与存储结构选型
java·服务器·redis
Wang's Blog2 小时前
Java 接入Redis: 字符串与哈希类型操作命令
java·服务器·redis
智慧物业老杨6 小时前
物业数字化落地思考:真正的转型,是底层数据秩序的重构
java·大数据·人工智能·微服务·系统架构
星空9 小时前
金蝶苍穹build.gradle配置
java·build.gradle
步行cgn12 小时前
Spring 基于 XML 的自动装配:byName 详解
java·后端·spring
大帅点兵12 小时前
Apache Ant 1.9.9 完整讲解
java