Java 泛型在编译时会进行类型擦除,以保证向后兼容性。这意味着在编译时,泛型信息会被移除,并且所有泛型类型参数会被替换为它们的上界(如果没有明确指定,则为 Object
)。
例如,泛型类型 List
在编译后会变成 List
,并且与类型参数 T
相关的操作会被替换为适当的类型检查或类型转换。
示例:
public class GenericClass<T> {
private T data;
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
}
编译后,上述代码实际上类似于:
public class GenericClass {
private Object data;
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
}
由于类型擦除的存在,Java 泛型在使用时存在一些限制:
由于类型擦除,无法在运行时确定泛型的实际类型,因此无法直接实例化泛型类型。
错误示例:
public class GenericClass<T> {
T instance = new T(); // 编译错误
}
同样,由于类型擦除,Java 不允许创建泛型类型的数组。
错误示例:
List<String>[] array = new List<String>[10]; // 编译错误
泛型不支持 Java 的基本类型(如 int
, char
, double
),只能使用它们的包装类(如 Integer
, Character
, Double
)。
错误示例:
List<int> list = new ArrayList<int>(); // 编译错误
instanceof
检查由于类型擦除,泛型类型的信息在运行时不可用,因此无法对泛型类型进行 instanceof
检查。
错误示例:
if (obj instanceof List<String>) { // 编译错误
// ...
}
正确的方式是:
if (obj instanceof List<?>) {
// ...
}
静态成员是类级别的,而泛型类型参数是实例级别的。因此,泛型类的静态成员不能使用泛型类型参数。
错误示例:
public class GenericClass<T> {
private static T data; // 编译错误
}
虽然 Java 泛型有以上限制,但通过合理的设计和使用,可以有效避免这些问题。例如:
extends
和 super
关键字)来限定泛型类型的范围。List
或其他集合类来替代。instanceof
检查时,可以使用 Class
对象或 getClass()
方法来替代。通过理解和掌握这些限制,您可以更好地利用 Java 泛型带来的优势。
在 Kotlin 中,泛型类型在编译时也会被擦除,这意味着在运行时,泛型类型信息不可用。这与 Java 的情况类似。以下是一些关键点:
类型擦除的表现:
T : Number
),那么在类型擦除后,T
会被替换为它的上界类型。Any
(Kotlin 中的顶级类型,相当于 Java 中的 Object
)。实例化泛型类型:
由于类型擦除,Kotlin 中同样无法实例化泛型类型。
class Box<T> {
fun createInstance(): T {
return T() // 编译错误
}
}
泛型数组:
Kotlin 中也不允许创建泛型类型的数组。
fun <T> createArray(): Array<T> {
return arrayOf<T>() // 编译错误
}
instanceof
检查(在 Kotlin 中是 is
检查):
在 Kotlin 中也不能直接对泛型类型进行 is
检查,因为类型在运行时被擦除了。
if (value is List<String>) { // 编译错误
// ...
}
正确的方式是使用无类型参数的 is
检查:
if (value is List<*>) {
// ...
}
reified
关键字Kotlin 提供了一个绕过类型擦除的解决方案,即在内联函数中使用 reified
关键字。使用 reified
可以让泛型类型参数在运行时保留其类型信息,这样就可以在运行时获取泛型类型。
示例:
inline fun <reified T> printTypeName() {
println(T::class)
}
fun main() {
printTypeName<String>() // 输出: class kotlin.String
}
通过使用 reified
关键字,Kotlin 能够保留泛型的实际类型,并在运行时访问它。
Kotlin 的泛型在编译时同样会经历类型擦除,与 Java 一致。不过,通过 reified
关键字,Kotlin 提供了一种在某些情况下保留泛型类型信息的方式,使得在运行时获取泛型类型成为可能。这使得 Kotlin 在泛型使用上比 Java 更灵活。
我有多年软件开发经验,精通嵌入式STM32,RTOS,Linux,Ubuntu, Android AOSP, Android APP, Java , Kotlin , C, C++, Python , QT。 如果您有软件开发定制需求,请联系我,电子邮件: [email protected]