reified关键字是用于Kotlin内联函数的,修饰内联函数的泛型,泛型被修饰后,在方法体里,能从泛型拿到泛型的Class对象,这与java是不同的,java需要泛型且需要泛型的Class类型时,是要把Class传过来的,但是kotlin不用了
您必须同意Kotlin是一种很棒的语言,这是因为与其他编程语言相比,它具有独特的功能。这些功能之一是Kotlin中的“Reified”关键字。等等,这个奇怪的术语叫“具体化”是什么?别担心,这就是今天博客的主题。在这篇博客中,我们将了解 Reified 类型。那么,让我们开始吧。
开始之前
大多数编程语言都有泛型的概念。泛型用于提供类或函数或某些属性的泛型/常规实现,即您将编写一次实现部分并将其用于各种数据类型。
例如,下面是一个泛型函数的代码:
fun <T> genericsExample(value: T) { println(value) } fun main() { genericsExample<String>("Learning Generics!") genericsExample<Int>(100) }
上面的泛型函数可用于任何类型的变量,即字符串,Int,布尔值等。因此,上述代码的输出将是:
Learning Generics! 100
现在,在函数中,让我们尝试找到使用的类型,即让我们有一个print语句,如果类型是String,Int,布尔值或其他什么东西,它将打印。genericsExample
T
T
fun <T> genericsExample(value: T) { println(value) prinln("Type of T: ${T::class.java}") }
上面的代码工作正常吗?不,您将收到错误。我们无法获取有关类型 T 的信息,因为泛型中存在类型擦除问题。因此,如果要访问的类型,那么我们可以将 的类作为参数传递给函数。Cannot use 'T' as reified type parameter
T
T
genericsExample
fun <T> genericsExample(classType: Class<T>, value: T) { println(value) println("Type of T: ${classType}") } fun main() { genericsExample<String>(String::class.java, "Learning Generics!") genericsExample<Int>(Int::class.java, 100) }
但这是最好的方法吗?可以使用这样的样板代码吗?不,绝对不是。
因此,这是Kotlin中Reified关键词的作用。让我们来了解一下。
Kotlin中Reified关键词
为了访问有关类类型的信息,我们在 Kotlin 中使用了一个名为 reified
的关键字。为了使用 reified 类型,我们需要使用内联函数。如果一个函数被标记为 ,那么无论在哪里调用该函数,编译器都会将函数的整个主体粘贴到那里。
inline
因此,以下是使用泛型的上述函数的更新代码(使用简化类型):
inline fun <reified T> genericsExample(value: T) { println(value) println("Type of T: ${T::class.java}") } fun main() { genericsExample<String>("Learning Generics!") genericsExample<Int>(100) }
下面是上述代码的输出:
Learning Generics! Type of T: class java.lang.String 100 Type of T: class java.lang.Integer
那么,引擎盖下发生了什么?为了找到它,我们需要看到上面例子的字节码:
public static final void genericsExample(Object value) { int $i$f$genericsExample = 0; boolean var2 = false; System.out.println(value); StringBuilder var10000 = (new StringBuilder()).append("Type of T: "); Intrinsics.reifiedOperationMarker(4, "T"); String var4 = var10000.append(Object.class).toString(); boolean var3 = false; System.out.println(var4); } public static final void main() { Object value$iv = "Learning Generics!"; int $i$f$genericsExample = false; boolean var2 = false; System.out.println(value$iv); String var5 = "Type of T: " + String.class; boolean var3 = false; System.out.println(var5); Object value$iv = 100; $i$f$genericsExample = false; var2 = false; System.out.println(value$iv); var5 = "Type of T: " + Integer.class; var3 = false; System.out.println(var5); }
由于我们在这里使用的是内联函数,因此该函数的代码将被复制并粘贴到我们将调用该函数的任何位置。此外,编译器正在将类型替换为实际类型,即 或。因此,无需显式传递类型。是不是很棒?是的,我知道,是的。我在博客的开头告诉过你????.T
String
Int
注意:在Java中,我们不能使用reified函数,因为那里不支持内联函数。
除了上述功能外,还可以使用reified完成其他操作。例如,我们可以使用具有相同参数和名称但返回类型不同的函数。
具有不同返回类型的函数
考虑一种情况,您希望将函数的参数的名称、编号和类型保持为相同,但返回类型不同。我们可以通过函数重载来做到这一点吗?我看看。
例如,假设您要打印一些消息,如果学生的分数高于90,并且如果分数低于90,则只想返回标记。因此,我们可以想到两个同名的函数 。第一个函数将作为输入,并且仅在 小于 90 时调用,这将仅返回整数标记。同样,当高于 90 时将调用另一个函数,并将以字符串形式返回一些消息。showMessage
marks
marks
marks
fun showMessage(marks: Int): Int { return marks } fun showMessage(marks: Int): String { return "Congratulations! you scored more than 90%"; }
上面的重载函数将引发错误,因为对于函数重载,参数的数量或参数类型应该不同,而不是返回类型。
因此,我们可以在此处使用关键字。修改后的代码将如下所示:reified
inline fun<reified T> showMessage(marks: Int): T { return when (T::class) { Int::class -> marks as T String::class -> "Congratulations! you scored more than 90%" as T else -> "Please enter valid type" as T } } fun main() { val intMarks: Int = showMessage(70) // returning integer value val stringMessage: String = showMessage(95) // returning string value println("Your marks: $intMarks \nMessage: $stringMessage") }
上述代码的输出将是:
Your marks: 70 Message: Congratulations! you scored more than 90%
在上面的示例中,您可以看到我们如何使用关键字从同一函数返回不同的数据类型(在我们的示例中为Int和String)。reified