泛型的概念
Java 泛型是一种类型安全的参数化类型机制,可以在编译期间检查类型匹配,避免因类型转换错误导致的运行期异常。泛型的基本思想是参数化类型,即将类型作为参数进行传递,以便在编译时进行类型检查和类型推断。
类型擦除
Java 泛型的底层实现是类型擦除,即在编译阶段泛型类型会被擦除成 Object 类型或者它们的上界类型。泛型类的类型参数被擦除后,它们的方法和属性会被替换成转换类型的 Object 类型或者上界类型。泛型方法的类型参数在编译时会被替换成 Object 类型或者上界类型,然后在运行时进行类型转换。
泛型类和泛型方法
泛型类
泛型类是指在类中使用泛型的情况。泛型类可以定义一个或多个类型参数,这些参数被用来声明类中的变量类型、方法参数类型、方法返回值类型等。在实例化泛型类时,需要在尖括号内指定类型参数的具体值。
public class MyGenClass<T> {
private T t;
public void setT(T t) {
this.t = t;
}
public T getT() {
return t;
}
}
在上面的例子中,我们定义了一个泛型类 MyGenClass,并使用类型参数 T 来指定变量类型,然后可以根据需要在实例化该类时指定具体类型。
MyGenClass<String> myGenClass = new MyGenClass<>();
myGenClass.setT("Hello World");
System.out.println(myGenClass.getT()); // 输出 Hello World
泛型方法
泛型方法是指在方法中使用泛型的情况。泛型方法可以定义一个或多个类型参数,这些参数被用来声明方法参数类型、方法返回值类型等。可以定义在非泛型类中或者泛型类中。
例如,在一个类中实现方法根据泛型类型判断两个对象是否相等:
public static <T> boolean isEqual(T first, T second) {
return first.equals(second);
}
在上面的例子中,我们定义了一个泛型方法 isEqual,并使用类型参数 T 来指定方法参数和返回值类型。
上界和通配符
上界
在 Java 中,可以使用 extends 关键字来定义一个类型参数的上界。这个上界限定了这个类型参数只能是指定的类型或者指定类型的子类。
例如,定义一个泛型方法 sort 可以保证元素必须具有可比较性:
public static <T extends Comparable<T>> void sort(List<T> list) {
Collections.sort(list);
}
在上面的例子中,我们定义了一个泛型方法 sort,并使用类型参数 T extends Comparable 来定义类型上界,要求元素必须具有可比较性。
通配符
在 Java 中,可以使用通配符 ? 来表示一个未知的泛型类型。通配符只能在参数化类型中使用,例如 List<?>。
通配符有两种类型:无界通配符和有界通配符。
- 无界通配符:使用 ? 表示一个未知且无界的类型,可以匹配任意类型。
- 有界通配符:使用 extends 关键字表示一个类型的上界,只能匹配指定的类型或者指定类型的子类。
例如,可以定义一个泛型方法打印列表中的元素:
public static void printList(List<?> list) {
for (Object obj : list) {
System.out.println(obj);
}
}
在上面的例子中,我们使用了无界通配符 ? 来表示一个未知的泛型类型。
public static void printList(List<? extends Number> list) {
for (Number obj : list) {
System.out.println(obj);
}
}
在上面的例子中,我们使用了有界通配符来表示仅匹配 Number 类型或者 Number 类型的子类。
类型检查和类型擦除
在使用 Java 泛型时,需要注意类型检查和类型擦除的问题。在程序编译时,编译器会进行类型检查,并将泛型类型转换为 Object 类型或者它们的上界类型。在程序运行时,JVM 会将泛型类型转换为 Object 类型或者它们的上界类型,然后进行类型转换。这个过程就是类型擦除。
在类型擦除的过程中,由于泛型类或者泛型方法中使用的类型参数被替换成了 Object 类型或者它们的上界类型,因此在程序运行时需要进行强制类型转换,否则可能会出现 ClassCastException 异常。
总结
Java 泛型是一种高效、灵活、可靠的参数化类型机制,它可以将类型作为参数进行传递,在编译期间就可以进行类型检查,避免了类型转换错误导致的运行期异常。泛型分为泛型类和泛型方法两种形式,可以使用类型参数和通配符来进行类型限制和类型推断。在使用泛型时需要注意类型检查和类型擦除的问题。
关注微信公众号:“小虎哥的技术博客”。我们会定期发布关于Java技术的详尽文章,让您能够深入了解该领域的各种技巧和方法,让我们一起成为更优秀的程序员👩💻👨💻!