【发布时间】:2017-04-23 10:15:42
【问题描述】:
我正在尝试获取类层次结构中某种类型的所有属性委托。这给我带来了一些问题。
首先,似乎没有直接的方法可以在 Kotlin 中获得类的超类。我尝试的第一种方法是使用 Java 的Class.getSuperclass:
private fun <T : Any> KClass<T>.getSuperclass(): KClass<in T>? = (java.superclass as? Class<out Any>)?.kotlin as KClass<in T>
但这需要未经检查的强制转换,因为 Kotlin 不允许我将 Class<in T> 转换回 Kotlin,因为显然在 T 中意味着它可能不是 Any,无论它可能是什么(“类型参数有一个不能满足捕获'in'投影的上限'Any'”)。
所以我尝试了一个纯 Kotlin 解决方案:首先获取所有超类,包括接口 (KClass.superclasses),然后过滤掉每个接口。但是KClass 上没有任何东西告诉我它是否是一个接口!所以我必须再次去Java。它再次需要未经检查的演员表,因为出于某种原因KClass.superclasses 的类型为List<KClass<*>> 而不是List<KClass<in T>>:
private fun <T : Any> KClass<T>.getSuperclass123(): KClass<in T>? = superclasses.firstOrNull { it.java.isInterface } as KClass<in T>?
我在这里遗漏了什么吗?我一定是。
现在对于实际问题,尝试获取类层次结构中的所有属性委托实例。首先我写了一个函数来获取一个类的实例:
private fun <T : Any> KClass<T>.getProperties(obj: T) =
declaredMemberProperties.also { it.forEach { it.isAccessible = true } }.asSequence().filter { it.getDelegate(obj) is MyPropertyDelegate }
工作正常。但当然,我还需要在超类中声明的所有属性。所以很自然地,我尝试将接收器更改为KClass<in T>,这当然导致我无法再拨打declaredMemberProperties。我该如何解决?
我已经尝试过使用KClass.memberProperties,但是如果子类覆盖了在父类中委派的属性,它就会失败。在这种情况下,它只会列出被覆盖的属性,这不允许我访问属性委托实例。
编辑: 我做了一些更多的测试,下面的 Java 代码编译得很好,正如我所期望的:
static <T> List<MyProperty> getProperties(KClass<? super T> clazz, T obj) {
return KClasses.getDeclaredMemberProperties(clazz).stream()
.map(p -> p.getDelegate(obj))
.filter(MyProperty.class::isInstance)
.map(MyProperty.class::cast)
.collect(Collectors.toList());
}
等效的 Kotlin 代码是什么?
编辑²: 超一流的东西也是如此。以下(尽管仍然是丑陋的解决方法)在 Java 中编译,但在 Kotlin 中不编译(此处省略 null-check):
static <T> KClass<? super T> getSuperClass(KClass<T> clazz) {
return JvmClassMappingKt.getKotlinClass(JvmClassMappingKt.getJavaClass(clazz).getSuperclass());
}
【问题讨论】:
标签: generics reflection kotlin