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

Java 泛型(Generics)详解与使用

一、什么是 Java 泛型?

泛型(Generics)是 Java 1.5 引入的一项重要特性,主要用于 类型参数化,允许在类、接口和方法定义时使用 类型参数(Type Parameter),从而提高代码的复用性类型安全性可读性


二、为什么需要泛型?

1. 解决类型安全问题

在没有泛型的时代,集合(如 ArrayList)存储的是 Object 类型,容易发生类型转换异常。

import java.util.ArrayList;

public class WithoutGenerics {
    public static void main(String[] args) {
        ArrayList list = new ArrayList();  // 没有指定类型
        list.add("Hello");
        list.add(100);  // 这里插入了一个整数

        for (Object obj : list) {
            // 需要强制转换,否则无法使用 String 方法
            String str = (String) obj;
            System.out.println(str.toUpperCase());  // 运行时可能报 ClassCastException
        }
    }
}

运行时会抛出 ClassCastException,因为 100 不能转换为 String


2. 使用泛型后,编译时即可发现错误

import java.util.ArrayList;

public class WithGenerics {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>(); // 指定类型为 String
        list.add("Hello");
        // list.add(100);  // 编译时直接报错,避免了运行时异常

        for (String str : list) {
            System.out.println(str.toUpperCase());
        }
    }
}
  • 类型安全:只能存储 String,避免了 ClassCastException
  • 可读性好:不需要强制类型转换。

三、泛型的基本用法

1. 泛型类

泛型类在定义时,使用 类型参数(T) 来表示类中可以使用的类型。

// 定义一个泛型类
class Box<T> {
    private T item;

    public void setItem(T item) {
        this.item = item;
    }

    public T getItem() {
        return item;
    }
}

public class GenericClassExample {
    public static void main(String[] args) {
        Box<String> stringBox = new Box<>();  // 指定 T 为 String
        stringBox.setItem("Hello");
        System.out.println(stringBox.getItem());

        Box<Integer> intBox = new Box<>();  // 指定 T 为 Integer
        intBox.setItem(100);
        System.out.println(intBox.getItem());
    }
}

类型参数常见约定:

  • T(Type):表示任意类类型
  • E(Element):集合中的元素类型
  • K(Key):键
  • V(Value):值

2. 泛型方法

泛型方法可以在 普通类或泛型类 中定义,方法的泛型参数只在方法内部生效

class Util {
    // 泛型方法
    public static <T> void print(T data) {
        System.out.println(data);
    }
}

public class GenericMethodExample {
    public static void main(String[] args) {
        Util.print("Hello");
        Util.print(123);
        Util.print(45.6);
    }
}
  • 需要声明在方法返回值之前
  • 泛型方法可以独立于类的泛型类型

3. 泛型接口

泛型接口通常用于 定义通用的操作,如数据存储、服务层 API

// 定义泛型接口
interface Repository<T> {
    void save(T data);
    T get();
}

// 实现泛型接口
class StringRepository implements Repository<String> {
    private String data;

    @Override
    public void save(String data) {
        this.data = data;
    }

    @Override
    public String get() {
        return data;
    }
}

public class GenericInterfaceExample {
    public static void main(String[] args) {
        Repository<String> repo = new StringRepository();
        repo.save("Hello");
        System.out.println(repo.get());
    }
}

也可以使用 泛型类 实现泛型接口:

class GenericRepository<T> implements Repository<T> {
    private T data;

    @Override
    public void save(T data) {
        this.data = data;
    }

    @Override
    public T get() {
        return data;
    }
}

四、泛型的高级用法

1. 泛型的通配符

通配符 ? 代表不确定的类型,主要用于:

  • 限定方法参数,使其接受不同的泛型类型。
  • 保证类型安全,避免强制转换。
(1)? extends T 上界通配符

限制为 T 及其子类,适用于只 读取数据 的场景。

import java.util.List;

public class WildcardExample {
    public static void printNumbers(List<? extends Number> list) {
        for (Number n : list) {
            System.out.println(n);
        }
    }

    public static void main(String[] args) {
        List<Integer> intList = List.of(1, 2, 3);
        List<Double> doubleList = List.of(1.1, 2.2, 3.3);

        printNumbers(intList);
        printNumbers(doubleList);
    }
}
  • 允许 IntegerDouble 作为 Number 的子类传入。
  • 不能往 list 里添加元素,否则会引发 编译错误,因为 ? extends Number 可能是 IntegerDouble,不确定具体类型。
(2)? super T 下界通配符

限制为 T 及其 父类,适用于 写入数据 的场景。

import java.util.List;
import java.util.ArrayList;

public class SuperWildcardExample {
    public static void addNumbers(List<? super Integer> list) {
        list.add(10);
        list.add(20);
    }

    public static void main(String[] args) {
        List<Number> numberList = new ArrayList<>();
        addNumbers(numberList);
        System.out.println(numberList);
    }
}
  • 允许 Integer 及其父类(如 Number)的 List 作为参数。
  • 可以往 list 里添加 Integer 类型的元素

2. 泛型擦除(Type Erasure)

Java 的泛型是 编译时 作用的,编译后会进行 类型擦除,即所有泛型参数都会被 替换为 Object(或其上界类型)。

class Box<T> {
    private T item;
    
    public void setItem(T item) {
        this.item = item;
    }
    
    public T getItem() {
        return item;
    }
}

编译后等价于:

class Box {
    private Object item;

    public void setItem(Object item) {
        this.item = item;
    }

    public Object getItem() {
        return item;
    }
}

影响:

  • 不能直接创建泛型数组T[] array = new T[10]; // 编译错误
  • 不能使用 instanceof 检测泛型类型if (obj instanceof Box<String>) // 编译错误

总结

特性说明
泛型类通过 <T> 定义,可以使用不同类型创建实例
泛型方法方法独立于类的泛型,可以使用不同类型参数
泛型接口定义通用接口,支持泛型类实现
通配符 ?? extends T 适用于读取,? super T 适用于写入
泛型擦除编译后泛型类型被擦除,限制了某些操作

注🚀:泛型是 Java 类型安全代码复用 的重要特性,熟练掌握可以大幅提升开发效率!

相关文章:

  • python多线程之ThreadLocal 笔记
  • 编程题 - 明明的随机数【JavaScript/Node.js解法】
  • 【知识】torchrun 与 torch.multiprocessing.spawn 的对比
  • python爬虫系列课程5:JavaScript语法介绍
  • 【Java】多线程篇 —— 线程池
  • 蓝桥杯 灯笼大乱斗【算法赛】
  • 设计模式之命令模式
  • Git操作指南:分支合并、回退及其他重要操作
  • json介绍、python数据和json数据的相互转换
  • GPIO概念
  • 分类预测 | Matlab实现GWO-LSSVM灰狼算法优化最小二乘支持向量机多特征分类预测
  • js加密之延伸requestAnimationFrame
  • 【Block总结】SAFMN,空间自适应调制与局部特征增强的协同设计|即插即用
  • 面试基础 ---深入解析JDK8类加载机制
  • Python核心技术,Django学习基础入门教程(附环境安装包)
  • iOS UICollectionViewCell 点击事件自动化埋点
  • 计算机毕业设计SpringBoot+Vue.js相亲网站(源码+文档+PPT+讲解)
  • Unity中动态切换光照贴图LightProbe的方法
  • C++实现3D(EasyX)详细教程
  • DeepSeek蒸馏TinyLSTM实操指南
  • “80后”南京大学天文与空间科学学院教授施勇加盟西湖大学
  • 英国警方再逮捕一名涉嫌参与首相住宅纵火案嫌疑人
  • 打击网络侵权盗版!四部门联合启动“剑网2025”专项行动
  • 上海市重大工程一季度开局良好,多项生态类项目按计划实施
  • 最高法、证监会:常态化开展证券纠纷代表人诉讼,降低投资者维权成本
  • 新任美国驻华大使庞德伟抵京履职,外交部回应