Как создать экземпляр объекта, используя значения параметров конструктора по умолчанию в Kotlin?

У меня есть класс данных со значениями по умолчанию.

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). Есть ли способ добиться этого в Котлине?

2 ответа

Параметры по умолчанию Kotlin не совместимы с Java-отражением, а это означает, что не существует простого способа их совместного использования, поскольку параметры по умолчанию Kotlin фактически работают с отдельным методом под капотом, которому также передается битовая маска, чтобы указать, какие аргументы являются значениями по умолчанию.

Есть два способа это исправить.

  • Используйте Kotlin отражения. Например, callBy Функция поддерживает параметры по умолчанию, их можно не указывать на карте.

  • использование @JvmOverloads генерировать перегрузку без параметра по умолчанию, который может быть вызван в Java.

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

Поскольку вы передаете значение NULL и не пропускаете аргумент, значение по умолчанию не принимается. https://kotlinlang.org/docs/reference/functions.html

Вы должны указать, что значение может быть обнуляемым. Положить ? после типа, если он обнуляем, а затем вы можете проверить и установить все, что вам нужно в конструкторе.

https://kotlinlang.org/docs/reference/null-safety.html

Использование в Котлине:

Значения по умолчанию в конструкторах принимаются только тогда, когда конкретный параметр этого конструктора ему вообще не передается. Это означает, что это делается для достижения различных комбинаций параметризованного конструктора. например,

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

принимает значения по умолчанию, когда используется как Bird(), Bird("голубь") или Bird (пол = "женщина") .

так что для решения вашей проблемы вы должны добавить? рядом с параметром категорий. как это,

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

и нет необходимости в emptyList() по умолчанию. Когда вы используете emptyList, как в вашем вопросе, вы должны проверить на ноль и пропустить этот параметр, как это

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())
Другие вопросы по тегам