如何使用 Kotlin 中的默认构造函数参数值实例化对象?

ros*_*euz 5 reflection kotlin kotlin-reflect kotlin-null-safety

我有默认值的数据类。

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 中实现这一目标?

hot*_*key 5

Kotlin 默认参数与 Java 反射不兼容,这意味着没有简单的方法可以将它们一起使用,因为 Kotlin 默认参数实际上与一个单独的方法一起工作,该方法还传递了一个位掩码来指定哪些参数是默认的。

有两种方法可以解决这个问题。


Vel*_*n V -1

在 Kotlin 中使用:

仅当该构造函数的特定参数根本未传递给构造函数时,才会采用构造函数中的默认值。这意味着这样做是为了实现参数化构造函数的各种组合。例如,

data class Bird (val name: String = "peacock", val gender: String = "male")
Run Code Online (Sandbox Code Playgroud)

用作 Bird()、Bird("dove") 或 Bird(gender ="female") 时采用默认值。

所以要解决你的问题,你必须添加 ? 在类别参数旁边。像这样,

data class Project(val code: String,
                   val name: String,
                   val categories: List<String>?)
Run Code Online (Sandbox Code Playgroud)

并且不需要emptyList()默认值。当您在问题中使用 emptyList 时,您必须检查 null 并省略该参数,如下所示

val project = if(categories == null)
       {
          Project(code,name)
       }
       else
       {
          Project(code,name,categories)
       }
Run Code Online (Sandbox Code Playgroud)

那是在另一个 kotlin 类中使用这个数据类时。

在JAVA中使用:

但是如果你想在任何 java 类中使用这个数据类,那么正如 @Hotkey 所说,默认情况下不支持它,因为 kotlin 通过使用一些底层方法来支持这个默认参数。

因此,为了使其与 java 类兼容,您必须添加@JvmOverloads注释,但不能像 @Hotkey 所说的那样必须这样注释

data class Project @JvmOverloads constructor(val code: String,
                                             val name: String,
                                             val categories: List<String>? = emptyList())
Run Code Online (Sandbox Code Playgroud)