0%

Java泛型

Java 泛型概述

Java 泛型(Generics) 是 JDK 1.5 引入的一项功能,允许在类、接口和方法中定义具有参数化类型的代码。泛型通过在编译时进行类型检查,提高了代码的安全性和可读性,减少了类型转换的需求。

泛型的优势

  • 类型安全:在编译时检查类型,避免运行时的 ClassCastException。

  • 代码重用性:支持定义通用的类、接口和方法,适用于多种数据类型。

  • 可读性和维护性:代码更加清晰,减少了显式类型转换的需要。

泛型的基本语法

  • 泛型类
1
2
3
4
5
6
7
8
9
10
11
12
13
package com.qust;

public class Box<T> {
private T item;

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

public T getItem() {
return item;
}
}
1
2
3
4
5
6
7
8
9
10
11
public class Main {
public static void main(String[] args) {
Box<String> stringBox = new Box<>();
stringBox.setItem("Hello World");
System.out.println(stringBox.getItem());

Box<Integer> intBox = new Box<>();
intBox.setItem(1);
System.out.println(intBox.getItem());
}
}
  • 泛型接口
1
2
3
4
5
// 定义一个泛型接口
public interface Pair {
K getKey();
V getValue();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package com.qust;

public class KeyValue<K,V> implements Pair<K, V>{
private K key;
private V value;

public KeyValue(K key, V value) {
this.key = key;
this.value = value;
}

@Override
public K getKey() {
return key;
}

@Override
public V getValue() {
return value;
}
}
1
2
3
4
5
6
public class Main {
public static void main(String[] args) {
Pair<String, Integer> pair = new KeyValue<> ("Age", 25);
System.out.println(pair.getKey() + ' ' + pair.getValue());
}
}
  • 泛型方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package com.qust;

public class GenericMethod {
public static <T> void printArray(T[] array) {
for(T element : array) {
System.out.println(element);
}
System.out.println();
}
public static void main(String[] args) {
Integer[] intArray = {1, 2, 3};
String[] strArray = {"A", "B", "C"};

printArray(intArray);
printArray(strArray);
}
}

泛型的类型限制

  • 通配符 ?

    • 表示未知类型,可用于读取时不确定具体类型。

      1
      2
      3
      4
      5
      public static void printList(List<?> list) {
      for (Object item : list) {
      System.out.println(item);
      }
      }
  • 边界限定

    • 上界通配符:<? extends T> 表示类型是 T 或其子类。

      1
      2
      3
      4
      5
      public static void printNumbers(List<? extends Number> list) {
      for (Number num : list) {
      System.out.println(num);
      }
      }
    • 下界通配符:<? super T> 表示类型是 T 或其父类。

      1
      2
      3
      public static void addNumbers(List<? super Integer> list) {
      list.add(1); // 允许添加 Integer 或其子类
      }
  • 类型参数边界

    • 限制泛型的范围。

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      public class Box<T extends Number> {
      private T item;

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

      public T getItem() {
      return item;
      }
      }

泛型的注意事项

  • 类型擦除

    • Java 泛型是通过类型擦除实现的,编译器在编译时会将泛型信息去掉,转换为原始类型(如 Object)。

      • 因此,不能在运行时获取泛型类型参数的信息,例如 List 和 List 在运行时是相同的。
  • 泛型不能用于静态字段或方法

    • 由于泛型类型在编译时确定,而静态成员属于类本身,与实例无关,因此泛型不能应用于静态成员。

      1
      2
      3
      4
      5
      6
      7
      public class GenericClass {
      // 静态变量不能使用泛型
      // private static T staticVar;

      // 静态方法也不能使用泛型
      // public static T getStaticValue() { return null; }
      }
  • 不能创建泛型数组

    1
    2
    // 不允许直接创建泛型数组
    List[] array = new ArrayList[10]; // 编译错误
  • 原始类型

1
2
3
Res res = new Res();
res.a = "Hello"; // 编译通过
res.a = 123; // 仍然编译通过,丢失了类型安全

没有指定泛型的数据类型,导致类型不安全。

常见应用场景

  • 集合框架:Java 的集合框架(如 ArrayList、HashMap 等)广泛使用了泛型。

  • 工具类:如 java.util.Collections 提供了许多泛型方法。

  • 类型安全容器:泛型可以实现自定义的类型安全容器。