面试题答案
一键面试-
类型擦除与泛型边界基础
- 类型擦除:在Kotlin(和Java类似)中,泛型主要是编译期的概念。在运行时,泛型类型信息会被擦除。例如,
List<String>
和List<Int>
在运行时都是List
类型,这使得直接在运行时获取泛型类型参数变得困难。 - 泛型边界:通过
where
关键字在Kotlin中定义泛型边界。例如,class MyClass<T : Number> where T : Comparable<T>
表示T
必须是Number
的子类且实现了Comparable<T>
接口。
- 类型擦除:在Kotlin(和Java类似)中,泛型主要是编译期的概念。在运行时,泛型类型信息会被擦除。例如,
-
获取泛型类型信息的方法
- 通过超类获取泛型类型:定义一个带泛型的超类,子类继承它时指定实际类型参数。
open class BaseClass<T> class SubClass : BaseClass<String>()
- 使用反射获取泛型类型:利用
Kotlin反射
,可以在运行时获取泛型类型信息。
val subClass = SubClass() val type = subClass::class.supertypes.first { it is ParameterizedType }.arguments[0].type println(type?.classifier)
这里通过获取
SubClass
的超类BaseClass
的参数化类型,进而获取到泛型参数的类型信息。 -
考虑类型擦除的限制及解决方案
- 限制:由于类型擦除,在运行时无法直接获取泛型参数的确切类型,如前面提到
List<String>
和List<Int>
运行时无法区分。 - 解决方案
- 类型令牌:定义一个类型令牌类,手动传递类型信息。
class TypeToken<T>(val type: KClass<T>) val stringToken = TypeToken<String>(String::class)
- 内联函数和重新ified类型参数:在Kotlin中,可以使用内联函数和
reified
关键字来避免类型擦除的部分影响。
inline fun <reified T> printType() { println(T::class) } printType<String>()
- 根据泛型类型参数进行特定操作
- 示例操作:假设我们有一个带有泛型边界的类
MyClass
,且希望根据泛型类型进行特定操作。
open class MyClass<T : Number> where T : Comparable<T> { fun compareValues(value1: T, value2: T): Int { return value1.compareTo(value2) } } class SubMyClass : MyClass<Double>()
- 在运行时操作:获取泛型类型后,可以根据其特性进行操作。
val subMyClass = SubMyClass() val type = subMyClass::class.supertypes.first { it is ParameterizedType }.arguments[0].type if (type == Double::class) { val result = subMyClass.compareValues(1.0, 2.0) println(result) }
这里根据获取到的泛型类型
Double
,调用compareValues
方法进行特定的比较操作。 - 限制:由于类型擦除,在运行时无法直接获取泛型参数的确切类型,如前面提到