返回

警惕泛型反噬!从入门到进阶,无痛掌握Java泛型核心知识点

后端

揭秘泛型:Java 中的灵活利器

泛型入门

在茫茫的代码海洋中,高手如林。初学者往往轻视泛型,认为它不过是个简单的类型参数。然而,当泛型展现出其灵活性,甚至成为隐藏陷阱时,你才会意识到它的复杂性。

泛型,顾名思义,是一种可被其他类型替换的类型。在 Java 中,泛型广泛应用于集合框架和算法库,为我们带来更灵活、更可重用的代码。

泛型语法

Java 中的泛型语法十分简单,只需在类名或方法名后添加尖括号,并在其中指定类型参数即可。例如:

class ArrayList<E> {
    private E[] elements;
}

其中,ArrayList 是泛型类,E 是类型参数,可以被任意类型取代。我们可以创建存储字符串的 ArrayList:

ArrayList<String> list = new ArrayList<>();

或存储整数的 ArrayList:

ArrayList<Integer> list = new ArrayList<>();

泛型的优势

泛型带来众多优势,其中最显著的有:

  • 代码复用性: 泛型提升代码的可重用性。我们可以使用泛型集合框架存储不同类型元素,无需为每种类型创建独立的集合类。
  • 类型安全: 泛型保障代码的类型安全性。使用泛型集合存储字符串,编译器将阻止添加其他类型元素。
  • 性能提升: 泛型优化代码性能。以存储字符串的泛型集合为例,编译器将生成更有效的代码。

泛型进阶

掌握泛型基础后,我们可以探索更高级的知识。

通配符

通配符是泛型的核心概念,允许使用泛型类型表示一组类型。例如,通配符 ? 表示所有类型:

ArrayList<?> list = new ArrayList<>();

这个 ArrayList 可存储任意类型元素,我们可以向其中添加元素:

list.add("Hello");
list.add(123);

边界类型

边界类型是通配符的变体,允许使用泛型类型表示具有相同父类的类型组。例如,边界类型 ? extends Number 表示所有继承自 Number 类的类型:

ArrayList<? extends Number> list = new ArrayList<>();

这个 ArrayList 可存储所有继承自 Number 类的元素,如 Integer、Double 和 BigDecimal:

list.add(123);
list.add(12.34);
list.add(new BigDecimal("123.45"));

泛型陷阱

使用泛型时,需要注意一些常见的陷阱:

空指针异常

泛型代码容易出现空指针异常。如果使用泛型集合存储对象,应确保在使用前检查对象是否为 null。否则,将抛出空指针异常。

ArrayList<String> list = new ArrayList<>();
list.add(null);
String s = list.get(0); // NullPointerException

类型擦除

Java 泛型在编译时进行类型擦除。这意味着泛型类型信息在编译后被移除。因此,运行时无法获取泛型类型信息。

ArrayList<String> list = new ArrayList<>();
list.add("Hello");
Object o = list.get(0); // Object

在这个例子中,我们无法在运行时知道 o 的类型是 String。

结语

泛型是 Java 中至关重要的特性。掌握泛型,可以编写出更灵活、更可重用、更高效的代码。然而,泛型也暗藏陷阱,需要我们谨慎使用。

常见问题解答

  1. 泛型的作用是什么?
    泛型允许类型化数据结构,从而提高代码可重用性、类型安全和性能。

  2. 如何创建泛型类?
    在类名后使用尖括号指定类型参数即可。

  3. 什么是通配符?
    通配符 ? 表示所有类型,而 ? extends T 表示所有继承自 T 类的类型。

  4. 什么是边界类型?
    边界类型指定泛型类型必须满足的约束。

  5. 使用泛型时有哪些注意事项?
    注意空指针异常和类型擦除问题,并确保在代码中正确使用泛型。