类型具体化是Kotlin的技巧之一.如果将泛型参数声明为,则仅在内联泛型函数中发生reified.
由于它是内联的,因此泛型参数可以是具体的class,而不仅仅是编译时类型信息.
你可以在Java中做一些不可能的事情:
你现在可以使用instanceofs(在Kotlin中,iss):
inline fun <reified T> f(a: Any) {
if (a is T) println("Hi!")
}
Run Code Online (Sandbox Code Playgroud)
这在Java中显然是不可能的.
您现在可以java.lang.Class<T>从generic参数获取java 实例.
inline fun <reified T> f(a: Any) {
println("Hey! my class is ${T::class.java}!")
if (a.javaClass == T::class.java) println("Hi!")
}
Run Code Online (Sandbox Code Playgroud)
另外,KClass还有:
inline fun <reified T> f(a: Any) {
println("KClass: ${T::class}")
}
Run Code Online (Sandbox Code Playgroud)
您可以使用空构造函数创建实例:
inline fun <reified T> f(a: Any) {
val o: T = T::class.java.newInstance()
}
Run Code Online (Sandbox Code Playgroud)
只有reified通用参数可以传递给其他reified函数.
inline fun <reified T> f(a: Any) {
g<T>(a)
}
inline fun <reified T> g(a: Any) {
if (a is T) println("Bingo!")
}
Run Code Online (Sandbox Code Playgroud)
这在科特林是不可能的:
inline fun <reified T> f(a: Any) {
}
fun <T> g(a: Any) {
f<T>(a) // error
}
Run Code Online (Sandbox Code Playgroud)
如果您使用其他语言reified在Kotlin中调用内联函数,则函数参数将为java.lang.Object.
您不能使用其他语言来调用reified函数.
就像,如果我们有一个具体的功能A.kt:
inline fun <reified T> f(a: T) = println(T::class.java)
Run Code Online (Sandbox Code Playgroud)
并使用反射获取它(它将被编译为私有):
Method method = AKt.class.getDeclaredMethod("f", Object.class);
Run Code Online (Sandbox Code Playgroud)
此代码将成功运行,没有例外.
但你不能调用它(我没有仔细阅读生成的字节码,对不起),因为它的实施:
private static final void f(Object a) {
Intrinsics.reifiedOperationMarker(4, "T"); // I didn't see
// the implementation of this line, so I thought it's
// possible to call it in other languages
Class var2 = Object.class;
System.out.println(var2);
}
Run Code Online (Sandbox Code Playgroud)
看看评论.看看定义reifiedOperationMarker:
public static void reifiedOperationMarker(int id, String typeParameterIdentifier) {
throwUndefinedForReified();
}
Run Code Online (Sandbox Code Playgroud)
它会抛出一个UnsupportedOperationException.
结论:reified只能用于Kotlin.
很难说Kotlin或Scala是否更好,因为Scala有更多的方法可以在运行时获取类型信息.
Alexey Romanov说Scala可以,但Kotlin不能:
在递归函数中使用ClassTags
我认为这可以通过使用函数内部的函数来解决:
inline fun <reified T> g(a: Any): Int {
var recur: ((Any) -> T)? = null
recur = { recur!!.invoke(it) as T } // use T is possible here
return recur(a)
}
Run Code Online (Sandbox Code Playgroud)
请注意,这只是一个语法上正确的例子.
当然,它是无限循环和不必要的演员.
他还说:
将它们存储在集合中并使用它们稍后调用ClassTag-using函数.
这是一个真正的问题,因为这需要noinlinelambdas,而Kotlin reified则基于内联.