Как создать экземпляр объекта, используя значения параметров конструктора по умолчанию в 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
Вы должны указать, что значение может быть обнуляемым. Положить ?
после типа, если он обнуляем, а затем вы можете проверить и установить все, что вам нужно в конструкторе.
Использование в Котлине:
Значения по умолчанию в конструкторах принимаются только тогда, когда конкретный параметр этого конструктора ему вообще не передается. Это означает, что это делается для достижения различных комбинаций параметризованного конструктора. например,
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())