Java 中的泛型是一种强大的编程特性,允许我们编写更加通用和类型安全的代码。本篇博客将深入探讨 Java 泛型的各个方面,包括泛型类、泛型方法、泛型接口以及泛型通配符。
1. 泛型类
首先,让我们看一个简单的泛型类的例子。在下面的代码中,我们定义了一个名为 GenericClass
的泛型类,它具有一个泛型参数 T
,并包含了构造方法、获取数据的方法和设置数据的方法。
public class GenericClass<T> {
private T data;
// 构造方法
public GenericClass(T data) {
this.data = data;
}
// 获取数据的方法
public T getData() {
return data;
}
// 设置数据的方法
public void setData(T data) {
this.data = data;
}
}
通过这个泛型类,我们可以创建具有不同类型的实例,例如:
// 使用泛型类,指定类型为String
GenericClass<String> stringGeneric = new GenericClass<>("Hello, Generics!");
// 使用泛型类,指定类型为Integer
GenericClass<Integer> intGeneric = new GenericClass<>(42);
2. 泛型方法
泛型不仅限于类,还可以用于方法。下面的代码展示了一个包含泛型方法的类 MyGeneric
,其中包括一个打印泛型类数据的方法。
public class MyGeneric {
// 泛型方法
public <T> void printData(GenericClass<T> generic) {
System.out.println(generic.getData());
}
// 其他泛型方法和示例省略...
}
通过这个泛型方法,我们可以在不同的上下文中打印不同类型的数据,使得代码更加灵活。
3. 泛型接口
Java 还支持泛型接口,这使得我们可以定义接口时使用泛型参数。下面的代码展示了一个泛型接口 GenericInterface
及其实现类 StringContainer
。
public interface GenericInterface<T> {
T getData();
void setData(T data);
}
public class StringContainer implements GenericInterface<String> {
private String data;
@Override
public String getData() {
return data;
}
@Override
public void setData(String data) {
this.data = data;
}
}
泛型接口提供了一种灵活的方式来定义可以处理多种类型数据的接口,并使得实现类更具通用性。
4. 泛型通配符
Java 的泛型还支持通配符,其中 <?>
表示未知类型。这种通配符的使用使得我们可以编写适用于多种泛型类型的代码。下面的代码展示了一个使用泛型通配符的方法。
public class MyGeneric {
// 使用泛型通配符的方法,接受任意泛型类型的参数
public static void printWildcardData(GenericClass<?> generic) {
System.out.println("Wildcard data: " + generic.getData());
}
// 其他代码和示例省略...
}
通过这个方法,我们可以传递任意泛型类型的参数,提高了代码的灵活性。
5. 泛型 record 类
在 Java 14(? 目前使用的是 Java 17) 中引入的 record
类型也支持泛型。下面的代码展示了一个泛型 record 类 Pair
。
public record Pair<T>(T first, T second) {
// 这里没有额外的方法,因为 record 自动生成了构造方法、getter 方法等
}
record
类提供了一种简洁的方式来定义不可变类,并通过泛型支持处理不同类型的数据。
6、完整代码
package com.lfsun.generic;
// 定义一个泛型类
public class GenericClass<T> {
private T data;
// 构造方法
public GenericClass(T data) {
this.data = data;
}
// 获取数据的方法
public T getData() {
return data;
}
// 设置数据的方法
public void setData(T data) {
this.data = data;
}
}
package com.lfsun.generic;
// 定义一个泛型接口
public interface GenericInterface<T> {
T getData();
void setData(T data);
}
package com.lfsun.generic;
// 定义一个泛型 record 类
public record Pair<T>(T first, T second) {
// 这里没有额外的方法,因为 record 自动生成了构造方法、getter 方法等
}
package com.lfsun.generic;
// 实现泛型接口的类
public class StringContainer implements GenericInterface<String> {
private String data;
@Override
public String getData() {
return data;
}
@Override
public void setData(String data) {
this.data = data;
}
}
package com.lfsun.generic;
// 定义一个包含泛型方法的类
public class MyGeneric {
// 泛型方法
public <T> void printData(GenericClass<T> generic) {
System.out.println(generic.getData());
}
// 泛型方法示例,接受任意类型的数组并打印
public static <E> void printArray(E[] array) {
for (E element : array) {
System.out.print(element + " ");
}
System.out.println();
}
// 使用泛型通配符的方法,接受任意泛型类型的参数
public static void printWildcardData(GenericClass<?> generic) {
System.out.println("Wildcard data: " + generic.getData());
}
public static void main(String[] args) {
// 使用泛型类,指定类型为String
GenericClass<String> stringGeneric = new GenericClass<>("Hello, Generics!");
// 使用泛型方法,打印泛型类的数据
MyGeneric myGeneric = new MyGeneric();
myGeneric.printData(stringGeneric);
// 使用泛型接口,实现类存储String类型数据
StringContainer stringContainer = new StringContainer();
stringContainer.setData("Generic Interface Example");
System.out.println("Data from interface: " + stringContainer.getData());
// 使用泛型方法,打印任意类型的数组
Integer[] intArray = {1, 2, 3, 4, 5};
String[] stringArray = {"apple", "banana", "orange"};
printArray(intArray);
printArray(stringArray);
// 使用泛型通配符的方法,打印任意泛型类型的数据
GenericClass<Double> doubleGeneric = new GenericClass<>(3.14);
printWildcardData(doubleGeneric);
// 创建 Pair 实例,指定泛型类型为 String
Pair<String> stringPair = new Pair<>("Hello", "World");
// 访问 record 自动生成的 getter 方法
System.out.println("First: " + stringPair.first());
System.out.println("Second: " + stringPair.second());
}
}