Java泛型的使用

发布于:2025-02-20 ⋅ 阅读:(174) ⋅ 点赞:(0)

Java 泛型的使用方法

泛型(Generics)是 Java 中的一种特性,允许在类、接口和方法中使用类型参数,提高代码的类型安全性可复用性。泛型最常用于集合类(如 List<T>Map<K, V>)和自定义类/方法


1. 泛型类

定义一个可以存储任意类型 T 的类:

// 定义泛型类,T 代表类型参数
class Box<T> {
    private T value;

    public void set(T value) {
        this.value = value;
    }

    public T get() {
        return value;
    }
}

// 使用泛型类
public class Main {
    public static void main(String[] args) {
        Box<String> stringBox = new Box<>();
        stringBox.set("Hello");
        System.out.println(stringBox.get()); // 输出: Hello

        Box<Integer> intBox = new Box<>();
        intBox.set(123);
        System.out.println(intBox.get()); // 输出: 123
    }
}

特点:

  • T 是一个类型参数,在使用 Box<T> 时才具体化(如 Box<String>)。
  • 泛型避免了强制类型转换,提高了类型安全性

2. 泛型方法

如果只需要某个方法支持泛型,而不是整个类,可以使用泛型方法:

public class Util {
    // 泛型方法,T 是方法级别的类型参数
    public static <T> void print(T item) {
        System.out.println(item);
    }

    public static void main(String[] args) {
        print("Hello");  // 输出: Hello
        print(100);      // 输出: 100
        print(3.14);     // 输出: 3.14
    }
}

特点:

  • <T> 在返回值 void 之前,表示该方法是泛型方法
  • T 的具体类型由调用时传入的参数决定。

3. 泛型接口

如果接口需要支持不同的数据类型,可以使用泛型:

// 定义泛型接口
interface DataProcessor<T> {
    void process(T data);
}

// 实现泛型接口(指定类型为 String)
class StringProcessor implements DataProcessor<String> {
    @Override
    public void process(String data) {
        System.out.println("Processing string: " + data);
    }
}

// 使用泛型接口
public class Main {
    public static void main(String[] args) {
        DataProcessor<String> processor = new StringProcessor();
        processor.process("Hello Generics!"); // 输出: Processing string: Hello Generics!
    }
}

特点:

  • 接口 DataProcessor<T> 可以支持不同的数据类型。
  • 实现类 StringProcessor 具体化 TString

4. 泛型通配符 ?

如果不关心泛型的具体类型,可以使用通配符 ?

4.1 ? extends T(上界通配符)

表示T 或 T 的子类,常用于读取数据

import java.util.*;

public class Main {
    public static void printList(List<? extends Number> list) {
        for (Number num : list) {
            System.out.println(num);
        }
    }

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

        printList(intList);   // 可以传 List<Integer>
        printList(doubleList); // 可以传 List<Double>
    }
}

解释:

  • ? extends Number:允许 List<Integer>List<Double> 作为参数(因为 IntegerDouble 都是 Number 的子类)。
  • 只能读取数据,不能 list.add(100)(编译错误)。

4.2 ? super T(下界通配符)

表示T 或 T 的父类,常用于写入数据

public class Main {
    public static void addNumbers(List<? super Integer> list) {
        list.add(100);
        list.add(200);
    }

    public static void main(String[] args) {
        List<Number> numberList = new ArrayList<>();
        addNumbers(numberList); // 允许 List<Number>

        List<Object> objectList = new ArrayList<>();
        addNumbers(objectList); // 允许 List<Object>
    }
}

解释:

  • ? super Integer:允许 List<Integer>父类(如 List<Number>List<Object>)。
  • 只能添加 Integer 或其子类,但取出时类型为 Object

5. 限定泛型类型

可以使用 extends 关键字限制泛型类型:

// 只允许 T 继承自 Number
class MathBox<T extends Number> {
    private T number;

    public MathBox(T number) {
        this.number = number;
    }

    public double square() {
        return number.doubleValue() * number.doubleValue();
    }
}

public class Main {
    public static void main(String[] args) {
        MathBox<Integer> intBox = new MathBox<>(5);
        System.out.println(intBox.square()); // 输出: 25.0

        MathBox<Double> doubleBox = new MathBox<>(3.2);
        System.out.println(doubleBox.square()); // 输出: 10.24

        // MathBox<String> strBox = new MathBox<>("Hello"); // ❌ 编译错误
    }
}

解释:

  • T extends Number:只允许 TNumber 及其子类(如 IntegerDouble)。
  • number.doubleValue() 确保可以对 T 进行数学运算。

6. 泛型的类型擦除

Java 泛型是伪泛型,在编译时起作用,运行时会擦除类型,变成 Object

import java.util.ArrayList;

public class Main {
    public static void main(String[] args) {
        ArrayList<String> list1 = new ArrayList<>();
        ArrayList<Integer> list2 = new ArrayList<>();

        System.out.println(list1.getClass() == list2.getClass()); // 输出: true
    }
}

解释:

  • 类型擦除ArrayList<String>ArrayList<Integer>运行时都是 ArrayList<Object>
  • 泛型只在编译阶段提供类型检查,运行时不保留具体类型。

总结

方式 说明 示例
泛型类 适用于存储、操作不同类型的数据 class Box<T> {}
泛型方法 仅某个方法使用泛型,不影响整个类 <T> void print(T item) {}
泛型接口 适用于多个实现类可以使用不同类型 interface DataProcessor<T> {}
通配符 ? ? extends T 适用于读取,? super T 适用于写入 List<? extends Number>
限定泛型 限制泛型的范围,必须是某个类的子类 class MathBox<T extends Number> {}
类型擦除 运行时泛型信息被擦除 List<String> → List<Object>

泛型让 Java 代码更安全灵活可复用,但需要理解它的限制(如类型擦除)和最佳实践


网站公告

今日签到

点亮在社区的每一天
去签到