我试图了解reified关键字的目的,显然它使我们能够对泛型进行反思。
但是,当我忽略它时,它也可以正常工作。有人在乎解释时,这使得实际的区别?
我试图了解reified关键字的目的,显然它使我们能够对泛型进行反思。
但是,当我忽略它时,它也可以正常工作。有人在乎解释时,这使得实际的区别?
Answers:
reified好处fun <T> myGenericFun(c: Class<T>)
在这类通用函数的主体中myGenericFun,您无法访问该类型,T因为它仅在编译时可用,而在运行时被擦除。因此,如果要将泛型类型用作函数体中的普通类,则需要显式传递该类作为参数,如中所示myGenericFun。
但是,如果inline使用带修饰符 的函数创建函数T,则T即使在运行时也可以访问的类型,因此您无需Class<T>额外传递。您可以T像对待普通类一样使用它,例如,您可能想检查变量是否是的实例 T,可以轻松地进行操作:myVar is T。
inline具有reified类型的此类函数T如下所示:
inline fun <reified T> myGenericFun()
reified工作您只能reified与inline功能结合使用。这种函数使编译器将函数的字节码复制到使用该函数的每个位置(该函数被“内联”)。当您调用带有修正类型的内联函数时,编译器知道用作类型实参的实际类型,并修改生成的字节码以直接使用相应的类。因此,在字节码中和在运行时,调用myVar is T变为成为myVar is String(如果type参数为String)。
让我们看一个示例,该示例显示了如何帮助reified您。我们要创建一个扩展功能String叫toKotlinObject,试图JSON字符串转换为纯科特林对象与函数的泛型类型指定的类型T。我们可以使用com.fasterxml.jackson.module.kotlin它,第一种方法是:
a)没有确定类型的第一种方法
fun <T> String.toKotlinObject(): T {
val mapper = jacksonObjectMapper()
//does not compile!
return mapper.readValue(this, T::class.java)
}
该readValue方法采用一种应该解析JsonObject为的类型。如果我们尝试获取Classtype参数的T,则编译器会抱怨:“不能将'T'用作化类型参数。请改用类。”
b)使用显式Class参数的解决方法
fun <T: Any> String.toKotlinObject(c: KClass<T>): T {
val mapper = jacksonObjectMapper()
return mapper.readValue(this, c.java)
}
解决方法是Class,T可以将的设为方法参数,然后将其用作的参数readValue。这是可行的,并且是通用Java代码中的常见模式。可以这样称呼:
data class MyJsonType(val name: String)
val json = """{"name":"example"}"""
json.toKotlinObject(MyJsonType::class)
c)科特林方式: reified
使用inline带有reified类型参数T的函数可以以不同的方式实现该函数:
inline fun <reified T: Any> String.toKotlinObject(): T {
val mapper = jacksonObjectMapper()
return mapper.readValue(this, T::class.java)
}
无需另外使用Classof T,T可以像普通类一样使用。对于客户端,代码如下所示:
json.toKotlinObject<MyJsonType>()
reified类型的内联函数不能从Java代码中调用。
简单
*已修正是在编译时授予使用权限(在函数内部访问T)
例如:
inline fun <reified T:Any> String.convertToObject(): T{
val gson = Gson()
return gson.fromJson(this,T::class.java)
}
使用像:
val jsonStringResponse = "{"name":"bruno" , "age":"14" , "world":"mars"}"
val userObject = jsonStringResponse.convertToObject<User>()
println(user.name)