其他
Kotlin Vocabulary | Reified: 类型擦除后再生计划
fun <T> printType(classType: Class<T>) {
print(classType::class.java)
}
泛型
List list = new ArrayList();
list.add("First String");
// 正常处理,没有错误
list.add(6);
String str = (String)list.get(1);
// 需要显示地进行转换和抛出异常
List<String> list = new ArrayList<>();
list.add("First String");
// 编译错误
list.add(6);
// 无需进行类型转换
String str = list.get(0);
类型擦除 (type erasure) https://en.wikipedia.org/wiki/Type_erasure
Reified
inline fun <reified T> printType() {
print(T::class.java)
}
fun printStringType(){
// 用 String 类型调用被 reified 修饰的泛型函数
printType<String>()
}
// 从字节码转换为 Java 的内联函数
public static final void printType() {
int $i$f$printType = 0;
Intrinsics.reifiedOperationMarker(4, "T");
Class var1 = Object.class;
boolean var2 = false;
System.out.print(var1);
}
// 从字节码转换为 Java 代码的调用方
public static final void printStringType() {
int $i$f$printType = false;
Class var1 = String.class;
boolean var2 = false;
System.out.print(var1);
}
inline fun <reified T> calculate(value: Float): T {
return when (T::class) {
Float::class -> value as T
Int::class -> value.toInt() as T
else -> throw IllegalStateException("Only works with Float and Int")
}
}
val intCall: Int = calculate(123643)
val floatCall: Float = calculate(123643)
一般来说,具有相同输入参数和不同返回类型的函数是不能够被重载的。使用内联函数,编译器可以在复制函数体时,同样将泛型返回类型替换为实际所表示的类型。如果您查看反编译后的 Java 代码,可以发现编译器在 intCall 变量中实际使用的是 Integer 类型,在 floatCall 变量中实际使用的是 Float 类型。
public final void call() {
float value = 123643.0F;
int $i$f$calculate = false;
KClass var5 = Reflection.getOrCreateKotlinClass(Integer.class);
Integer var10000;
if (Intrinsics.areEqual(var5, Reflection.getOrCreateKotlinClass(Float.TYPE))) {
var10000 = (Integer)value;
} else {
if (!Intrinsics.areEqual(var5, Reflection.getOrCreateKotlinClass(Integer.TYPE))) {
throw (Throwable)(new IllegalStateException("Only works with Float and Int"));
}
var10000 = (int)value;
}
//这里用到了 Integer
int intCall = ((Number)var10000).intValue();
int $i$f$calculate = false;
KClass var6 = Reflection.getOrCreateKotlinClass(Float.class);
Float var8;
if (Intrinsics.areEqual(var6, Reflection.getOrCreateKotlinClass(Float.TYPE))) {
var8 = value;
} else {
if (!Intrinsics.areEqual(var6, Reflection.getOrCreateKotlinClass(Integer.TYPE))) {
throw (Throwable)(new IllegalStateException("Only works with Float and Int"));
}
var8 = (Float)(int)value;
}
float floatCall = ((Number)var8).floatValue(); //这里用到了 Float
}
Reified 允许您在使用泛型来进行编程的同时,还能够在运行时获取到泛型所代表的类型信息,这在之前是无法做到的。当您需要在内联函数中使用到类型信息,或者需要重载泛型返回值时,您可以使用 reified。使用 reified 不会带来任何性能上的损失,但是如果被内联的函数过于复杂则,还是可能会导致性能问题。因为 reified 必须使用内联函数,所以要保证内联函数的简短,并且遵循使用内联函数的最佳实践,以免让性能受到损失。
推荐阅读