Java泛型的用法及T.class的获取过程解析
什么是泛型
泛型是Java语言中的一个重要特性,它允许我们在类或方法中预先声明使用的类型,并在实例化时指定具体的类型,从而达到代码复用的效果。
例如,在传统的Java编程中,如果要编写一个通用的Stack类,可以存储各种类型的数据,可以这样写:
public class Stack {
private Object[] array;
private int size;
public Stack(int capacity) {
this.array = new Object[capacity];
this.size = 0;
}
public void push(Object item) {
array[size++] = item;
}
public Object pop() {
if (size == 0) {
throw new RuntimeException("Stack is empty");
}
return array[--size];
}
}
这个Stack类使用Object类型存储元素,但是,它有一个明显的弱点:无法在编译时检查元素类型的正确性。我们可以装入任何类型的对象,而不必遵循应有的类型约束。
使用泛型,我们可以将Stack类型参数化。例如:
public class Stack<T> {
private T[] array;
private int size;
public Stack(int capacity) {
this.array = (T[]) new Object[capacity];
this.size = 0;
}
public void push(T item) {
array[size++] = item;
}
public T pop() {
if (size == 0) {
throw new RuntimeException("Stack is empty");
}
return array[--size];
}
}
这里,我们将Stack声明为一个泛型类,使用类型参数T代表类型的占位符。在实例化时,我们可以指定具体的类型,例如:
Stack<String> stackOfString = new Stack<>(10);
Stack<Integer> stackOfInteger = new Stack<>(10);
泛型类的基本用法
类型参数
泛型类的类型参数用尖括号框起来,可以在声明类时指定,如:
public class List<T> {
// ...
}
这里的T是类型参数,可以在类中使用。泛型类有一个好处:它可以使用与类型无关的代码来定义类,并且可以在实例化时指定类型。例如:
List<Integer> list = new List<>();
...
List<String> list2 = new List<>();
方法泛型
方法泛型的声明类似于泛型类的声明,只需要在方法返回类型前加上类型参数即可:
public class Stack {
// ...
public <T> void push(T item) {
// ...
}
public <T> T pop() {
// ...
}
}
这里,我们使用了类型参数T来声明方法push和pop。在调用时,可以使用具体的类型来替换T:
stack.push(100);
stack.push("Hello");
通配符类型
通配符类型是指一个泛型实参是其它泛型实参或非泛型类型的基类或接口时,使用的特殊类型。使用?表示通配符类型。例如:
public void process(List<?> list) {
// do something
}
这里,我们使用了通配符类型?,表示list中的元素类型可以是任意类型。
获取T.class的过程
在一些泛型场景中,如果需要获取泛型参数的class对象,可以利用Java的反射机制来实现。可以通过在方法中添加一个类型参数,利用Javac的类型推断机制来获取对应的class对象。
例如,在下面的示例代码中,我们演示了如何利用T.class来创建一个泛型数组。
import java.lang.reflect.Array;
public class GenericArray<T> {
private T[] array;
public GenericArray(Class<T> type, int size) {
this.array = (T[]) Array.newInstance(type, size);
}
public void printType() {
System.out.println(array.getClass().getTypeName());
}
public static void main(String[] args) {
GenericArray<Integer> ga = new GenericArray<>(Integer.class, 10);
ga.printType();
}
}
在上面的示例代码中,我们在构造器中显示地传递了类型参数Class
GenericArray<String> ga = new GenericArray<>(String.class, 10);
ga.printType();
示例1:利用泛型实现一个简单的缓存系统
下面是一个简单的缓存系统,可以缓存任意类型的对象。缓存的数据存储在一个Map中,使用泛型类型T和K代表缓存数据的类型和键类型:
import java.util.HashMap;
import java.util.Map;
public class Cache<T, K> {
private Map<K, T> cache = new HashMap<>();
public void put(K key, T value) {
cache.put(key, value);
}
public T get(K key) {
return cache.get(key);
}
public static void main(String[] args) {
Cache<String, Integer> cache = new Cache<>();
cache.put(1, "Hello");
cache.put(2, "World");
System.out.println(cache.get(1));
System.out.println(cache.get(2));
}
}
在上面的示例代码中,我们将泛型参数T和K用于缓存类Cache中,实现了一个简单的缓存系统。
示例2:使用泛型来实现数组转换
在下面的示例代码中,我们将一个数组中的元素转换为另一个数组中的元素,同样可以使用泛型来实现:
import java.lang.reflect.Array;
public class ArrayConverter {
public static <T, K> K[] convert(T[] src, Class<K> type) {
K[] dest = (K[]) Array.newInstance(type, src.length);
for (int i = 0; i < src.length; i++) {
dest[i] = (K) src[i];
}
return dest;
}
public static void main(String[] args) {
Integer[] ints = {1, 2, 3};
String[] strings = ArrayConverter.convert(ints, String.class);
for (String s : strings) {
System.out.println(s);
}
}
}
在上面的示例代码中,我们使用了方法泛型来指定方法的类型参数,并利用Java的反射机制来获取对应的class对象。在main方法中,我们使用了ArrayConverter.convert方法将数组中的元素从Integer类型转换为String类型。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Java泛型的用法及T.class的获取过程解析 - Python技术站