我正在玩反思,我出现了这个问题.通过::class语法使用绑定类引用时,我得到一个协变的KClass类型:
fun <T> foo(entry: T) {
with(entry::class) {
this // is instance of KClass<out T>
}
}
Run Code Online (Sandbox Code Playgroud)
正如我可以从文档中学习的那样,这将返回对象的确切类型,以防它是子类型的实例T,因此是方差修饰符.但是这会阻止检索在T类中声明的属性并获取它们的值(这是我正在尝试做的)
fun <T> foo(entry: T) {
with(entry::class) {
for (prop in memberProperties) {
val v = prop.get(entry) //compile error: I can't consume T
}
}
}
Run Code Online (Sandbox Code Playgroud)
我发现一个解决方案是javaClass.kotlin在对象引用上使用扩展函数,而不是使用不变类型:
fun <T> foo(entry: T) {
with(entry.javaClass.kotlin) {
this // is instance of KClass<T>
}
}
Run Code Online (Sandbox Code Playgroud)
这样,我在运行时获得了确切的类型,并且可以使用该类型.
有趣的是,如果我使用超类型而不是泛型,使用后一种方法我仍然可以访问正确的类型,而不需要方差:
class Derived: Base()
fun foo(entry: Base) {
with(entry.javaClass.kotlin) {
println(this == …Run Code Online (Sandbox Code Playgroud) 我有默认值的数据类。
data class Project(
val code: String,
val name: String,
val categories: List<String> = emptyList())
Run Code Online (Sandbox Code Playgroud)
当某些值为空时,Java 反射无法实例化类。我得到了例外
java.lang.IllegalArgumentException: Parameter specified as non-null is null: method Project.<init>, parameter categories
Run Code Online (Sandbox Code Playgroud)
这是因为java.lang.reflect.Constructor<T>.instantiateClass方法需要不为空的参数。
我有类型信息,我有构造函数定义,但我不确定如何调用构造函数以便它使用默认值(这些值来自数据库并且categories可以是null)。有没有办法在 Kotlin 中实现这一目标?
我在我的项目中使用org.jetbrains.kotlin:kotlin-reflect库(包含在gradle依赖项中).
该应用程序一直没有任何问题,但在将android gradle插件升级到最新版本3.1.0之后,应用程序开始在一台设备上崩溃(Nexus 5,Android 4.4.3).日志如下:
E/AndroidRuntime:FATAL EXCEPTION:kotlin.jvm.KotlinReflectionNotSupportedError:在运行时找不到Kotlin反射实现.确保你在kotlin.jvm.internal.ClassReference.error(ClassReference.kt:86)的类路径中有kotlin-reflect.jar,位于kotlin.jvm.internal.ClassReference.getSimpleName(ClassReference.kt:23)
我认为这不是预期的行为,但也许有人找到了解决方法/解决方案?
现在我被迫将android gradle插件降级到3.0.1以防止应用程序崩溃.
====================
我试图重新创建导致崩溃的环境,但是我没有设法重现崩溃.因为这只发生在较旧的Android版本(pre-L)上,并且在升级引入一些dex优化的android gradle插件之后,我的猜测是它在某种程度上相关.
====================
对于将此问题标记为重复的人:
我不确定是否可以更清楚:其他票证是否缺少依赖性.我在build.gradle中有kotlin反映依赖.此外,我的应用程序适用于较高的Android版本以及将android gradle插件降级到3.0.1之后.如果缺少依赖项,则无法使用任何版本的android gradle插件.因此,其他问题的答案对此无效.
KClass定义为public interface KClass<T : Any> : KDeclarationContainer, KAnnotatedElement, KClassifier
这很棘手,因为 a 的类String?应该是KClass<String>,但不可能获得。
给出下面的 3 个示例(它们本质上应该执行相同的工作),其中 1 个无法编译,其他返回相同的运行时类型。
inline fun <reified T> test1(): Any = T::class
inline fun <reified T: Any> test2(): KClass<T> = T::class
inline fun <reified T> test3(): KClass<T> = T::class // does not compile
test1<String?>() // class kotlin.String
test1<String>() // class kotlin.String
test2<String?>() // does not compile
test2<String>() // class kotlin.String
Run Code Online (Sandbox Code Playgroud)
问题的重点是问:如何获得 的运行时行为和test1的编译时行为(和安全性)test2?
编辑:问题的最后一个附录是另一个示例,它演示了获取可为空类型的类的问题。
inline fun <reified T> …Run Code Online (Sandbox Code Playgroud) 我有以下代码:
import kotlin.reflect.KProperty1
infix fun <T, R> KProperty1<T, R>.eq(value: R) {
println(this.name + " = $value")
}
infix fun <T, R> KProperty1<T, R>.eq(value: KProperty1<T, R>) {
println(this.name + " = " + value.name)
}
data class Person(val age: Int, val name: String, val surname: String?)
fun main() {
Person::age eq 1 // Valid. First function
Person::name eq "Johan" // Valid. First function
Person::name eq Person::name // Valid. Second function
Person::age eq 1.2f // Valid, but it shouldn't be. First function …Run Code Online (Sandbox Code Playgroud) 在 Android Studio 3.4.1 中从 Kotlin 1.3.21 更新到 1.3.30+ 时,我们收到以下构建错误:
e: java.lang.IllegalStateException: failed to analyze: java.lang.AssertionError: annotation tree hasn't been attributed yet: @kotlin.Metadata(mv = {1, 1, 15}, bv = {1, 0, 3}, k = 1, d1 = {"\u0000$\n\u0002\u0018\u0002\n\u0000\n\u0002\u0010\u0000\n\u0002\u0018\u0002\n\u0000\n\u0002\u0018\u0002\n\u0000\n\u0002\u0010\b\n\u0000\n\u0002\u0018\u0002\n\u0002\b\u0002\b&\u0018\u0000*\b\b\u0000\u0010\u0001*\u00020\u00022\b\u0012\u0004\u0012\u0002H\u00010\u0003B\u001f\u0012\u0006\u0010\u0004\u001a\u00020\u0005\u0012\b\b\u0001\u0010\u0006\u001a\u00020\u0007\u0012\u0006\u0010\b\u001a\u00020\t\u00a2\u0006\u0002\u0010\n\u00a8\u0006\u000b"}, d2 = {"Lde/thermomess/field/ui/viewholder/BaseViewHolder;", "T", "", "Lcom/xroot/android/ui/recyclerview/RecyclerViewHolder;", "context", "Landroid/content/Context;", "layoutResId", "", "parent", "Landroid/view/ViewGroup;", "(Landroid/content/Context;ILandroid/view/ViewGroup;)V", "app_betaDebug"})
Run Code Online (Sandbox Code Playgroud)
@kotlin.Metadata 背后的所有内容都不同,但在此之前它保持不变。对于 Kotlin 1.3.21 及更早版本,一切工作正常。
我们使用 @kotlin.Metadata 来检查一个类是否是 Gson TypeAdapterFactory 的 Kotlin 类
private val Class<*>.isKotlinClass: Boolean
get() = declaredAnnotations.find { it.annotationClass.java.name == "kotlin.Metadata" } != null
Run Code Online (Sandbox Code Playgroud)
以及通过混淆规则跳过自定义注释 …
我正在开发一个使用反射的库,我想操作给定 KClass 的所有属性/函数。
使用该KClass::members属性,我可以操作所有可访问的成员(根据文档),即:公共、内部和受保护的字段、属性和函数。但我看不到私人的。
使用 Java 反射,我可以使用 来查看所有字段(包括私有字段)Class.getDeclaredFields(),同样我可以使用 来查看私有方法Class.getDeclaredMethods()。
有没有办法使用 kotlin 反射 API 来做到这一点?
在 Kotlin 1.4.30 中,当我输入
open interface I
Run Code Online (Sandbox Code Playgroud)
Kotlin 编译器警告我modifier 'open' is redundant for 'interface'。这完全有道理:当然接口是开放的,否则它们将毫无用处。
但是,反射库似乎与此相矛盾:
interface I
println(I::class.isOpen) // prints 'false'
Run Code Online (Sandbox Code Playgroud)
这有什么意义?的KDocisOpen非常简短:
true如果这个类是开放的。
Kotlin 中“开放”的确切定义是什么? 我认为这意味着“开放被该文件之外的类进行子类型化的可能性”。
我有一个包含一些数据类的包,我尝试使用 Kotlin 反射在运行时访问构造函数clazz.primaryConstructor,一切都按预期工作,但是当我启用 R8 时,数据类元数据被删除,例如当我检查它是否KClass isData返回 false 时并且主构造函数也为 null,这仅在启用 R8 时发生。我尝试了一切,包括@keep向所有数据类添加注释并添加规则以将所有内容保留在模型包中,我还添加了这些规则
-keep class kotlin.reflect.**
-keep class kotlin.Metadata { *; }
Run Code Online (Sandbox Code Playgroud)
但仍然没有运气,知道出了什么问题或如何解决这个问题吗?
提前致谢。
Kotlin反射库定义了KDeclarationContainer哪个Represents an entity which may contain declarations of any other entities, such as a class or a package.
this::class返回KClass,扩展KDeclarationContainer,但我如何得到父KDeclarationContainer(a KPackage?)