跳到主要内容

Java 泛型

提示
  1. 泛型类和方法:Java中的泛型允许创建可以与不同类型数据一起使用的通用类和方法,提高了代码重用性。
  2. 有界类型:使用extends关键字限制泛型参数的类型,确保泛型只接受特定类型(或其子类型)的数据。
  3. 泛型的优势:泛型增强了编译时的类型检查,避免了类型转换错误,并且在集合框架中广泛应用,提供了类型安全的数据操作。

Java 泛型允许我们创建单个类、接口和方法,这些类、接口和方法可以与不同类型的数据(对象)一起使用。

这有助于我们重用代码。

注意泛型 不能与基本类型(如 intfloatchar 等)一起使用。

Java 泛型类

我们可以创建一个可以与任何类型的数据一起使用的类。这样的类被称为泛型类。

以下是在 Java 中创建泛型类的方法:

示例:创建泛型类

class Main {
public static void main(String[] args) {

// 使用 Integer 数据初始化泛型类
GenericsClass<Integer> intObj = new GenericsClass<>(5);
System.out.println("泛型类返回: " + intObj.getData());

// 使用 String 数据初始化泛型类
GenericsClass<String> stringObj = new GenericsClass<>("Java 编程");
System.out.println("泛型类返回: " + stringObj.getData());
}
}

// 创建泛型类
class GenericsClass<T> {

// T 类型的变量
private T data;

public GenericsClass(T data) {
this.data = data;
}

// 返回 T 类型变量的方法
public T getData() {
return this.data;
}
}

输出

泛型类返回: 5
泛型类返回: Java 编程

在上面的示例中,我们创建了一个名为 GenericsClass 的泛型类。这个类可以用来处理任何类型的数据。

class GenericsClass<T> {...}

这里,尖括号 <> 中的 T 表示类型参数。在 Main 类中,我们创建了两个 GenericsClass 的对象:

  • intObj - 这里,类型参数 T 被替换为 Integer。现在,GenericsClass 用于处理整数数据。
  • stringObj - 这里,类型参数 T 被替换为 String。现在,GenericsClass 用于处理字符串数据。

Java 泛型方法

类似于泛型类,我们也可以创建一个可以与任何类型的数据一起使用的方法。这样的方法被称为泛型方法。

以下是在 Java 中创建泛型方法的方法:

示例:创建泛型方法

class Main {
public static void main(String[] args) {

// 使用 Integer 数据初始化类
DemoClass demo = new DemoClass();

// 泛型方法处理 String
demo.<String>genericsMethod("Java 编程");

// 泛型方法处理整数
demo.<Integer>genericsMethod(25);
}
}

class DemoClass {

// 创建泛型方法
public <T> void genericsMethod(T data) {
System.out.println("泛型方法:");
System.out.println("传递的数据: " + data);
}
}

输出

泛型方法:
传递的数据: Java 编程
泛型方法:
传递的数据: 25

在上面的示例中,我们创建了一个名为 genericsMethod 的泛型方法。

public <T> void genericsMethod(T data) {...}

在这里,类型参数 <T> 被插入到修饰符 public 之后和返回类型 void 之前。

我们可以通过在方法名之前的括号内放置实际类型 <String><Integer> 来调用泛型方法。

demo.<String>genericMethod("Java 编程");

demo.<Integer>genericMethod(25);

注意:我们可以在不包括类型参数的情况下调用泛型方法。例如,

demo.genericsMethod("Java 编程");

在这种情况下,编译器可以根据传递给方法的值匹配类型参数。

有界类型

通常,类型参数 可以接受任何数据类型(基本类型除外)。

然而,如果我们只想将泛型用于某些特定类型(如只接受数字类型的数据),那么我们可以使用有界类型。

在有界类型的情况下,我们使用 extends 关键字。例如,

<T extends A>

这意味着 T 只能接受 A 的子类型的数据。

示例:有界类型

class GenericsClass <T extends Number> {

public void display() {
System.out.println("这是一个有界类型泛型类。");
}
}

class Main {
public static void main(String[] args) {

// 创建 GenericsClass 的对象
GenericsClass<String> obj = new GenericsClass<>();
}
}

在上述示例中,我们创建了一个名为 GenericsClass 的类。注意表达式,

<T extends Number>

这里,GenericsClass 是用有界类型创建的。这意味着 GenericsClass 只能用于处理 Number 的子类型数据(如 IntegerDouble 等)。

然而,我们使用 String 创建了一个泛型类的对象。在这种情况下,我们将得到以下错误。

GenericsClass<String> obj = new GenericsClass<>();
^
原因:推断变量 T 有不兼容的边界
等式约束条件:String
下限:Number
其中 T 是一个类型变量:
T extends Number 声明于类 GenericsClass

Java 泛型的优势

1. 代码重用性

借助 Java 中的泛型,我们可以编写可以与不同类型的数据一起工作的代码。例如,

public <T> void genericsMethod(T data) {...}

这里,我们创建了一个泛型方法。这个相同的方法可以用来对整数数据、字符串数据等进行操作。

2. 编译时类型检查

泛型的类型参数提供了有关泛型代码中使用的数据类型的信息。例如,

// 使用泛型
GenericsClass<Integer> list = new GenericsClass<>();

在这里,我们知道 GenericsClass 仅与 Integer 数据一起工作。

现在,如果我们尝试向这个类传递非 Integer 的数据,程序将在编译时生成错误。

3. 与集合一起使用

Java 中的集合框架使用了泛型的概念。例如,

// 创建一个字符串类型的 ArrayList
ArrayList<String> list1 = new ArrayList<>();

// 创建一个整数类型的 ArrayList
ArrayList<Integer> list2 = new ArrayList<>();

在上述示例中,我们使用了相同的 ArrayList 类 来处理不同类型的数据。

ArrayList 类似,Java 中的其他集合(如 LinkedListQueueMaps 等)也是泛型的。