Kotlin中的关键字关键词究竟是干什么的?

我试图理解关键字关键字的目的,显然它允许我们对泛型进行思考 。

但是,当我离开它时,它工作得很好。 任何人都在意解释什么时候会产生实际的差异?

为什么我们需要它

在一个普通的通用函数fun <T> myGenericFun(c:Class<T>)中,不能访问T类型,因为它只在编译时可用,但在运行时擦除 。 因此,如果你想使用泛型类型作为函数体中的普通类,你需要显式地传递类作为参数,就像我的例子。

如果你使用一个具体化的T做了一个inline函数,那么即使在运行时也可以访问T的类型,因此你不需要另外传递Class<T> 。 你可以像使用普通的类一样使用T ,比如你可能想要检查一个变量是否是T一个实例 ,你可以很容易的做到: myVar is T

这样的功能如下所示:

 inline fun <reified T> myGenericFun() 

胡德如何运作

你只能使用与inline函数结合使用。 这样的函数使编译器将函数的字节码复制到函数正在被使用的每个地方(函数被“内联”)。 当您使用具体化类型调用内联函数时, 编译器知道用作类型参数的实际类型,并修改生成的字节码以直接使用相应的类。 因此,像myVar is T这样的调用myVar is T成为myVar is String ,如果类型参数是String ,在字节码和运行时。

让我们来看一个例子,其中reified是真正有用的。 我们要为String创建一个名为toKotlinObject的扩展函数,它试图将JSON字符串转换为由函数类型T指定的Kotlin对象。 我们可以使用com.fasterxml.jackson.module.kotlin来解决这个问题,第一种方法如下:

编译错误

 fun <T> String.toKotlinObject(): T { val mapper = jacksonObjectMapper() //does not compile! return mapper.readValue(JsonObject(this).encode(), T::class.java) } 

readValue方法要我们告诉哪个类型应该解析JsonObject 。 我们尝试使用类型参数T并获得它的Class

这不起作用,编译器告诉我们: “不能使用'T'作为实体类型参数,而是使用类。”

没有通过的工作示例

 fun <T> String.toKotlinObject(c: Class<T>): T { val mapper = jacksonObjectMapper() return mapper.readValue(JsonObject(this).encode(), c) } 

下一步是将显式的T类直接作为参数传递给readValue 。 这是有效的,这是我们在Java中所做的。 它可以这样调用:

 "{}".toKotlinObject(MyJsonType::class.java) 

具体化了

使用带有特定类型参数Tinline函数可以实现我们的功能,如下所示:

 inline fun <reified T> String.toKotlinObject(): T { val mapper = jacksonObjectMapper() return mapper.readValue(JsonObject(this).encode(), T::class.java) } 

T不需要另外通过T ClassT可以像普通类一样使用。 对于客户端代码如下所示:

 "{}".toKotlinObject<MyJsonType>() 

重要

内联指定函数不能从Java代码中调用