返回

Kotlin 和 Java 泛型的局限性:泛型擦除和通配符

Android

泛型擦除

泛型擦除是 Java 和 Kotlin 编译器在编译时将泛型信息从字节码中删除的过程。这意味着在运行时,泛型类型参数被替换为它们的原始类型。例如,以下 Java 代码:

List<String> names = new ArrayList<>();

在编译后,将变为:

List names = new ArrayList();

泛型擦除的主要优点是它可以提高代码的性能。因为编译器不需要在运行时检查类型安全性,所以它可以生成更快的代码。然而,泛型擦除也有一些缺点。例如,它使得在运行时无法确定泛型类型参数的实际类型。这可能会导致类型安全问题,例如 ClassCastException。

通配符

通配符是 Java 和 Kotlin 中用于表示未知类型的符号。它可以用于声明变量、方法参数和返回值。例如,以下 Java 代码:

List<?> names = new ArrayList<>();

声明了一个可以存储任何类型元素的列表。

通配符可以分为两种类型:

  • 有界通配符 :有界通配符指定了未知类型必须是某个类型的子类型或超类型。例如,以下 Java 代码:
List<? extends Number> numbers = new ArrayList<>();

声明了一个可以存储任何 Number 类型或 Number 的子类型的列表。

  • 无界通配符 :无界通配符不指定任何类型限制。例如,以下 Java 代码:
List<?> names = new ArrayList<>();

声明了一个可以存储任何类型元素的列表。

星投影

星投影是 Java 和 Kotlin 编译器用来表示泛型类型参数的擦除类型的符号。例如,以下 Java 代码:

List<?> names = new ArrayList<>();

在编译后,将变为:

List names = new ArrayList<>();

星投影的主要优点是它可以提高代码的可读性。因为星投影可以明确地表示泛型类型参数已被擦除,所以它可以帮助开发者更好地理解代码。

泛型的局限性:类型安全和可读性

泛型擦除、通配符和星投影都可能会导致类型安全问题。例如,以下 Java 代码:

List<String> names = new ArrayList<>();
names.add(new Integer(1));

这段代码会在运行时抛出 ClassCastException 异常,因为 ArrayList 只能存储 String 类型元素。这是因为泛型擦除使得编译器无法在编译时检查类型安全性。

为了解决这个问题,我们可以使用有界通配符来指定列表只能存储 String 类型元素。例如,以下 Java 代码:

List<? extends String> names = new ArrayList<>();
names.add("John");

这段代码不会抛出 ClassCastException 异常,因为编译器可以在编译时检查类型安全性。

结论

泛型擦除、通配符和星投影都是 Java 和 Kotlin 中泛型的局限性。它们可能会导致类型安全问题和可读性问题。然而,通过理解这些概念并正确使用它们,我们可以编写出安全可靠的代码。