跳到主要内容

Java 泛型

Java 泛型(generics)是 JDK 5 中引入的一个新特性, 泛型提供了编译时类型安全检测机制,该机制允许程序员在编译时检测到非法的类型。

泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。

假定我们有这样一个需求:写一个排序方法,能够对整型数组、字符串数组甚至其他任何类型的数组进行排序,该如何实现? 答案是可以使用 Java 泛型。 使用 Java 泛型的概念,我们可以写一个泛型方法来对一个对象数组排序。然后,调用该泛型方法来对整型数组、浮点数数组、字符串数组等进行排序。

Java泛型(Generics)是一种编程语言功能,它允许在编写代码时定义可重用的类和接口,而不必为每种可能的类型编写重复的代码。泛型可以提高代码的可读性、重用性和类型安全性。

Java泛型的主要概念

  1. 类型参数:泛型类或接口使用尖括号<>内的类型参数表示其通用类型。

    例如,List<T>中的T就是一个类型参数,表示该列表可以存储任何类型的元素。类型参数通常用大写字母表示,常见的有T(Type)、E(Element)、K(Key)和V(Value)。

  2. 泛型类和接口:泛型类和接口在定义时使用类型参数,用于指定成员变量、方法参数和返回值的类型。

    例如,Java集合框架中的List<E>接口和ArrayList<E>类就是泛型接口和类的示例。

    public interface List<E> {
    void add(E e);
    E get(int index);
    }

    public class ArrayList<E> implements List<E> {
    // 实现细节
    }
  3. 实例化泛型类型:当创建泛型类或接口的实例时,需要为类型参数指定具体的类型。

    例如,List<String>表示一个包含字符串元素的列表,List<Integer>表示一个包含整数元素的列表。

    List<String> stringList = new ArrayList<String>();
    List<Integer> integerList = new ArrayList<Integer>();

    从Java 7开始,可以使用菱形操作符<>省略构造函数中的类型参数,编译器会自动推断出正确的类型。

    List<String> stringList = new ArrayList<>();
    List<Integer> integerList = new ArrayList<>();
  4. 类型擦除:为了保持与没有泛型的旧代码的兼容性,Java泛型在编译时会被擦除。

    这意味着泛型类型信息在运行时不可用。例如,在运行时,List<String>List<Integer>都被当作List来处理。这有时会导致一些限制,如不能直接创建泛型数组。

  5. 有界类型参数:可以使用extends关键字限制泛型类型参数的取值范围。

    例如,<T extends Comparable<T>>表示类型参数T必须实现Comparable<T>接口。

    public class SortedPair<T extends Comparable<T>> {
    private final T first;
    private final T second;

    public SortedPair(T first, T second) {
    if (first.compareTo(second) <= 0) {
    this.first = first;
    this.second = second;
    } else {
    this.first = second;
    this.second = first;
    }
    }
    // 其他方法
    }
  6. 通配符:通配符?可以用于表示未知的泛型类型。

    它通常用于泛型方法的参数类型,以实现更灵活的多态性。通配符可以与extendssuper关键字结合使用,表示上界和下界。

    // 使用通配符的泛型方法
    public static void printList(List<?> list) {
    for (Object item : list) {
    System.out.println(item);
    }
    }

java 中泛型标记符:

  • E - Element (在集合中使用,因为集合中存放的是元素)
  • T - Type(Java 类)
  • K - Key(键)
  • V - Value(值)
  • N - Number(数值类型)
  • - 表示不确定的 java 类型

如何理解泛型

刚开始学习Java时,理解泛型可能有些困难。但不用担心,可以通过以下简化的方法来逐步理解Java泛型:

  1. 泛型的目的:泛型的主要目的是提高代码的重用性和类型安全性。

    当需要为多种类型创建相似的类或方法时,泛型可以帮助你避免编写重复代码。

  2. 泛型类和泛型接口:泛型类和泛型接口使用类型参数(如TE等)来表示通用类型。这允许我们在实例化这些类或接口时为其指定具体的类型。

    例如,Java集合框架中的List<E>就是一个泛型接口。

    public interface List<E> {
    void add(E e);
    E get(int index);
    }
  3. 实例化泛型类型:当你创建泛型类或接口的实例时,需要为类型参数指定具体的类型。

    例如,List<String>表示一个包含字符串元素的列表,List<Integer>表示一个包含整数元素的列表。

    List<String> stringList = new ArrayList<String>();
    List<Integer> integerList = new ArrayList<Integer>();

    这样,你可以在编译时获得更好的类型检查,避免运行时出现类型错误。

  4. 通配符:通配符?用于表示未知的泛型类型,可以让你编写更灵活的代码。通常情况下,通配符用于泛型方法的参数类型。

    例如,以下方法可以打印任何类型的列表:

    public static void printList(List<?> list) {
    for (Object item : list) {
    System.out.println(item);
    }
    }

随着对Java编程的熟练度提高,将更好地理解泛型的概念和应用。在实际编程过程中,多尝试使用泛型并阅读相关文档,有助于加深对泛型的理解。

泛型方法和泛型类有什么区别

泛型方法和泛型类都是Java泛型的重要组成部分,它们的主要区别在于应用范围和定义方式:

泛型类

  1. 应用范围:泛型类中的类型参数可以在整个类中使用,包括类的属性、方法参数和方法返回类型。

  2. 定义方式:在类名后面添加尖括号<>,并在括号内指定类型参数。类型参数通常用单个大写字母表示,如TE等。

    例如,一个简单的泛型类Box

    public class Box<T> {
    private T content;

    public T getContent() {
    return content;
    }

    public void setContent(T content) {
    this.content = content;
    }
    }

泛型方法

  1. 应用范围:泛型方法中的类型参数仅在该方法内有效,不能在其他方法中使用。

  2. 定义方式:在方法返回类型之前添加尖括号<>,并在括号内指定类型参数。类型参数通常用单个大写字母表示,如TE等。

    例如,一个简单的泛型方法printArray

    public class Utils {
    public static <T> void printArray(T[] array) {
    for (T item : array) {
    System.out.println(item);
    }
    }
    }

总结一下,泛型类允许你在整个类中使用类型参数,而泛型方法则限制在特定方法内。在实际编程中,你可能会遇到泛型类与泛型方法结合使用的情况,以实现更高级别的泛型编程。