【发布时间】:2014-11-18 10:29:55
【问题描述】:
我使用以下初始化:
val entityClass = javaClass<Class<T>>()
var entity = entityClass.newInstance().newInstance()
但这是错误的,并导致IllegalAccessExceptionjava.lang.Class.newInstance(Class.java:1208)
【问题讨论】:
我使用以下初始化:
val entityClass = javaClass<Class<T>>()
var entity = entityClass.newInstance().newInstance()
但这是错误的,并导致IllegalAccessExceptionjava.lang.Class.newInstance(Class.java:1208)
【问题讨论】:
如果让 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 的参数并使用构造函数引用。 Here's my related question 关于构造函数引用,代码如下:
fun <T> foo2(factory: () -> T) {
var entity: T = factory()
}
fun test() {
foo2(::Object)
}
【讨论】:
new 关键字,表示“T 必须是可构造的”。
entityClass 通过使函数与 reified 内联。
感谢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 的后代。
【讨论】: