6

我有具有默认值的数据类。

data class Project(
    val code: String,
    val name: String,
    val categories: List<String> = emptyList())

当某些值为空时,Java 反射无法实例化类。我得到了例外

java.lang.IllegalArgumentException: Parameter specified as non-null is null: method Project.<init>, parameter categories

这是因为java.lang.reflect.Constructor<T>.instantiateClass方法需要不为空的参数。

我有类型信息,我有构造函数定义,但我不确定如何调用构造函数以便它使用默认值(这些值来自数据库并且categories可以是null)。有没有办法在 Kotlin 中实现这一点?

4

2 回答 2

6

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

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

  • 使用 Kotlin 反射。例如,该callBy函数支持默认参数,它们可以从映射中省略。

  • 用于@JvmOverloads生成不带默认参数的重载,可在 Java 中调用。

    @JvmOverloads
    data class Project(
        val code: String,
        val name: String,
        val categories: List<String> = emptyList()
    )
    
于 2017-09-15T19:07:20.253 回答
-1

在 Kotlin 中使用:

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

data class Bird (val name: String = "peacock", val gender: String = "male")

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

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

data class Project(val code: String,
                   val name: String,
                   val categories: List<String>?)

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

val project = if(categories == null)
       {
          Project(code,name)
       }
       else
       {
          Project(code,name,categories)
       }

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

在 JAVA 中使用:

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

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

data class Project @JvmOverloads constructor(val code: String,
                                             val name: String,
                                             val categories: List<String>? = emptyList())
于 2017-09-15T18:20:25.073 回答