- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
我正在尝试实现checked Stack<E>
基于 Kotlin 中的 java 数组。但是我在将 KClass 与我的通用参数类型一起使用时遇到问题 <E>
允许空值。
Java Generic types are not available in runtime, but array types are available. I want to use this feature so that there is built-in type checking in runtime.
More details about the checked/unchecked can be found here https://stackoverflow.com/a/530289/10713249
interface Stack<E> {
fun push(elem: E)
fun pop(): E
}
class CheckedStack<E>(elementType: Class<E>, size: Int) : Stack<E> {
companion object {
inline fun <reified E> create(size: Int): CheckedStack<E> {
//**compile error here**
return CheckedStack(E::class.javaObjectType, size)
}
}
@Suppress("UNCHECKED_CAST")
private val array: Array<E?> = java.lang.reflect.Array.newInstance(elementType, size) as Array<E?>
private var index: Int = -1
override fun push(elem: E) {
check(index < array.size - 1)
array[++index] = elem
}
override fun pop(): E {
check(index >= 0);
@Suppress("UNCHECKED_CAST")
return array[index--] as E
}
}
我希望这段代码能像这样工作:
fun main() {
val intStack = CheckedStack.create<Int>(12) // Stack must store only Integer.class values
intStack.push(1); //[1]
intStack.push(2); //[1, 2]
val stackOfAny: Stack<Any?> = intStack as Stack<Any?>;
stackOfAny.push("str") // There should be a runtime error
}
但是我有编译错误
Error:(39, 42) Kotlin: Type parameter bound for T in val <T : Any> KClass<T>.javaObjectType: Class<T>
is not satisfied: inferred type E is not a subtype of Any
为了修复它,我需要绑定(bind)类型参数 <E : Any>
但我需要堆栈能够处理可为 null 的值 <T : Any?>
.如何解决?
为什么 KClass 声明为 KClass<T : Any>
不是KClass<T : Any?>
?
UPD:如果使用 E::class.java
就可以了相反 E::class.javaObjectType
因为属性val <T> KClass<T>.java: Class<T>
具有类型参数 <T>
带注释 @Suppress("UPPER_BOUND_VIOLATED")
.
但是属性val <T : Any> KClass<T>.javaObjectType: Class<T>
类型为 <T : Any>
.
在我的例子中,Kotlin 将 Int 编译为 Integer.class 而不是 int(在我的例子中)。但我不确定它是否会始终有效。
最佳答案
可空类型本身不是类,因此它们没有类对象。这就是 KClass
的类型参数具有 Any
上限的原因。
您可以在可为空的具体化类型上调用 ::class.java
,但它会被评估为与在相应的非空类型上进行相同调用时相同的类对象。因此,如果将 E::class.javaObjectType
替换为 E::class.java
,将在运行时检查元素的类型,但不会进行空值检查。
如果需要空检查,可以自行添加。我还建议将数组创建移至工厂方法。方法如下:
class CheckedStack<E>(private val array: Array<E?>, private val isNullable: Boolean) : Stack<E> {
companion object {
// This method invocation looks like constructor invocation
inline operator fun <reified E> invoke(size: Int): CheckedStack<E> {
return CheckedStack(arrayOfNulls(size), null is E)
}
}
private var index: Int = -1
override fun push(elem: E) {
if (!isNullable) elem!!
check(index < array.size - 1)
array[++index] = elem
}
override fun pop(): E {
check(index >= 0)
@Suppress("UNCHECKED_CAST")
return array[index--] as E
}
}
关于java - 为什么 KClass 声明为 KClass<T : Any> and not KClass<T> so that the type argument can be nullable,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58259374/
我是一名优秀的程序员,十分优秀!