泛型
目录泛型的定义
Java泛型是在Java SE 5中引入的一种特性,它允许你为你的类、接口和方法指定类型参数,从而使得代码更加类型安全和灵活。泛型的本质是参数化类型,即在编译时提供类型信息,以确保类型的正确性。
java复制public class Box<T> {
private T t;
public void set(T t) { this.t = t; }
public T get() { return t; }
}
泛型的作用
- 类型安全:泛型提供了编译时类型检查,减少了运行时类型错误。
- 消除类型转换:使用泛型可以减少类型转换,使代码更简洁。
- 代码复用:泛型允许你编写更通用的类和方法,可以用于不同的数据类型。
泛型的特性
Java泛型是Java 5 引入的一个特性,它为Java语言带来了类型安全和代码复用性。以下是Java泛型的主要特性:
-
类型安全:
泛型的主要目的是提供类型安全。使用泛型,你可以在编译时检查类型错误,避免在运行时出现类型转换异常。 -
消除类型转换:
泛型消除了在集合中存储和检索对象时需要进行的类型转换。这使得代码更简洁,减少了出错的可能性。 -
代码复用:
泛型允许你编写可以用于多种类型的通用类和方法,从而提高代码复用率。 -
类型参数化:
泛型允许你为类、接口、方法定义类型参数,这些参数在实例化或调用时指定。 -
类型推断:
Java编译器能够推断泛型的类型,这减少了代码的冗余,使得代码更加简洁。 -
泛型通配符:
使用问号?
可以定义一个通配符类型,它可以接受任何类型的参数。 -
类型上限:
使用extends
关键字,可以为泛型指定一个类型上限,即泛型参数必须是上限类型或其子类型。 -
类型下限(不常用):
使用super
关键字,可以为泛型指定一个类型下限,但这种做法在Java中不常用。 -
协变与逆变:
泛型是协变的,意味着如果S
是T
的子类型,则List<S>
是List<T>
的子类型。逆变通常用于方法参数,但Java泛型不支持泛型的逆变。 -
类型擦除:
泛型的类型信息在编译时存在,但在运行时被擦除,这意味着运行时无法直接获取泛型的类型信息。 -
泛型数组限制:
由于类型擦除,Java不允许创建泛型类型的数组。 -
非重新实例化:
泛型类和接口不能被重新实例化,即不能使用泛型参数创建它们的子类。 -
与现有代码的兼容性:
泛型被设计为与现有非泛型代码兼容,这允许逐步将泛型集成到现有代码库中。 -
限制与原始类型:
当泛型类型使用未指定实际类型时,它被称为原始类型(如List
而不是List<String>
)。使用原始类型会失去泛型的类型安全。 -
桥方法:
当泛型类继承非泛型类时,编译器会生成桥方法来保持二进制兼容性。
泛型的使用
定义泛型类
public class Box<T> {
private T item;
public void setItem(T item) {
this.item = item;
}
public T getItem() {
return item;
}
}
使用泛型类
Box<String> stringBox = new Box<>();
stringBox.setItem("Hello, World!");
String item = stringBox.getItem();
泛型接口
public interface Stack<T> {
void push(T item);
T pop();
}
泛型方法
public class Utils {
public static <T> void printArray(T[] array) {
for (T item : array) {
System.out.println(item);
}
}
}
使用泛型方法
String[] strings = {"a", "b", "c"};
Utils.printArray(strings);
Integer[] numbers = {1, 2, 3};
Utils.printArray(numbers);
泛型通配符
public class WildcardTest {
public static void printArrayWithBounds(List<? extends Number> list) {
for (Number n : list) {
System.out.println(n);
}
}
public static void printArrayWithUnboundedWildcard(List<?> list) {
for (Object obj : list) {
System.out.println(obj);
}
}
}
泛型的类型限定
public class GenericClass<T extends Comparable<T>> {
// T 必须实现了 Comparable 接口
public void compare(T a, T b) {
a.compareTo(b);
}
}
泛型方法的类型限定
public class MathUtils {
public static <T extends Number> double calculate(T a, T b, MathOperation<T> operation) {
return operation.performOperation(a, b);
}
}
interface MathOperation<T extends Number> {
double performOperation(T a, T b);
}
泛型的类型擦除
Java泛型的类型信息在编译时被检查,但在运行时会被擦除,这意味着你不能直接获取泛型的类型信息:
Box<String> box = new Box<>();
System.out.println(box.getItem().getClass()); // 正确使用
System.out.println(box.getClass().getTypeParameters()); // 编译错误,因为类型信息已被擦除
泛型数组的限制
由于类型擦除,Java不允许创建泛型数组:
List<String>[] lists = new List<String>[10]; // 编译错误
List<String>[] lists = new ArrayList<String>[10]; // 正确
使用原始类型
有时,为了与旧代码兼容,你可能需要使用原始类型:
List list = new ArrayList(); // 使用原始类型
list.add("String"); // OK
list.add(1); // 编译时不报错,但运行时会抛出 ClassCastException
使用泛型时,应该尽量避免使用原始类型,以保持类型安全。
通过这些用法,你可以创建类型安全、灵活且可重用的代码。Java泛型是Java语言中一个非常重要的特性,广泛应用于集合框架、自定义数据结构和算法实现中。
标签:Java,item,List,类型,泛型,public From: https://www.cnblogs.com/luoyiwen123/p/18347777