Как правильно создать новый экземпляр универсального класса в kotlin?

Я использую следующую инициализацию:

val entityClass = javaClass<Class<T>>()
var entity = entityClass.newInstance().newInstance()

но это неправильно и вызывает IllegalAccessException на java.lang.Class.newInstance(Class.java:1208)

1 ответ

Решение

Если вы позволите IntelliJ добавить явную информацию о типе, вы увидите, что entityClass на самом деле типа Class<Class<String>>, Я не уверен, что ты этого хочешь. В строке 2 вы сначала создаете экземпляр Class<T> а затем один из T но это все равно невозможно, потому что общая информация о T теряется во время выполнения. Кроме того, вы не можете создавать экземпляры объектов класса напрямую.

Решение

Одним из возможных решений было бы добавить параметр типа Class<T> к вашей функции или классу и использовать его для создания таких объектов, как это.

fun <T> foo(entityClass: Class<T>) {
    var entity: T = entityClass.newInstance()
}

fun test() {
    foo(Object::class.java)
}

Но на самом деле есть более элегантное решение без использования отражения. Определить параметр типа метода () -> T и использовать ссылки на конструктор. Вот мой связанный вопрос о ссылках на конструктор и вот код:

fun <T> foo2(factory: () -> T) {
    var entity: T = factory()
}

fun test() {
    foo2(::Object)
}

Благодаря Kirill Rakhman я написал аналогичный ответ (для Android-адаптера). Разница здесь в параметре класса.

private fun <T> createItem(
    viewGroup: ViewGroup,
    layoutRes: Int,
    method: (View) -> T
): T {
    val view = LayoutInflater.from(viewGroup.context).inflate(layoutRes, viewGroup, false)
    return method(view) // Creates T(view).
}

Тогда используйте это так:

override fun onCreateViewHolder(viewGroup: ViewGroup, viewType: Int): AbstractViewHolder {
    return when (viewType) {
        LOADER -> createItem(viewGroup, R.layout.row_loader, ::LoaderViewHolder)
        DATE -> createItem(viewGroup, R.layout.row_date, ::DateViewHolder)
        else -> throw IllegalStateException("Wrong class")
    }
}

Вот LoaderViewHolder а также DateViewHolder являются потомками AbstractViewHolder.

Другие вопросы по тегам