Java 为什么将KClass声明为KClass<;T:任何>;而不是KClass<;T>;这样类型参数就可以为空

Java 为什么将KClass声明为KClass<;T:任何>;而不是KClass<;T>;这样类型参数就可以为空,java,generics,kotlin,Java,Generics,Kotlin,我试图基于Kotlin中的java数组实现选中的堆栈。但是我在将KClass与允许空值的泛型参数类型一起使用时遇到了一个问题 Java泛型类型在运行时不可用,但数组类型可用。我想使用这个特性,以便在运行时有内置的类型检查 有关已选中/未选中项目的更多详细信息,请参见此处 接口堆栈{ 趣味推送(要素:E) 有趣的流行音乐 } class CheckedStack(elementType:class,size:Int):堆栈{ 伴星{ 内联乐趣创建(大小:Int):CheckedStack{ //

我试图基于Kotlin中的java数组实现选中的
堆栈。但是我在将KClass与允许空值的泛型参数类型
一起使用时遇到了一个问题

Java泛型类型在运行时不可用,但数组类型可用。我想使用这个特性,以便在运行时有内置的类型检查

有关已选中/未选中项目的更多详细信息,请参见此处

接口堆栈{
趣味推送(要素:E)
有趣的流行音乐
}
class CheckedStack(elementType:class,size:Int):堆栈{
伴星{
内联乐趣创建(大小:Int):CheckedStack{
//**此处编译错误**
返回CheckedStack(E::class.javaObjectType,大小)
}
}
@抑制(“未选中的_CAST”)
private val array:array=java.lang.reflect.array.newInstance(elementType,size)作为数组
私有变量索引:Int=-1
覆盖乐趣推送(要素:E){
检查(索引=0);
@抑制(“未选中的_CAST”)
将数组[索引--]返回为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
}
fun main(){
val intStack=CheckedStack.create(12)//堆栈只能存储Integer.class值
intStack.push(1);//[1]
intStack.push(2);//[1,2]
val stackOfAny:Stack=intStack作为堆栈;
stackOfAny.push(“str”)//应该有运行时错误
}
但是我有编译错误

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
错误:(39,42)Kotlin:val KClass中T的类型参数绑定。javaObjectType:Class
不满足:推断类型E不是任何类型的子类型
为了修复它,我需要绑定类型参数
,但我需要堆栈能够处理可空值
。如何修复它

为什么KClass声明为
KClass
而不是
KClass

UPD:如果使用
E::class.java
而不是
E::class.javaObjectType
因为属性
val KClass.java:Class
具有类型param
,带有注释
@Suppress(“违反上限”)

但是属性
val KClass.javaObjectType:Class
具有类型


在我的例子中,Kotlin将Int编译为Integer.class,而不是Int(在我的例子中)。但是我不确定它是否总是能正常工作。

可空类型本身不是类,因此它们没有类对象。这就是为什么
KClass
的类型参数有一个
Any
上限

您可以对可为null的具体化类型调用
::class.java
,但它将被计算为与对相应非null类型的相同调用相同的类对象。因此,如果将
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
    }
}
类CheckedStack(private val数组:array,private val isNullable:Boolean):堆栈{
伴星{
//此方法调用类似于构造函数调用
内联运算符调用(大小:Int):CheckedStack{
返回CheckedStack(arrayOfNulls(大小),null为E)
}
}
私有变量索引:Int=-1
覆盖乐趣推送(要素:E){
如果(!isNullable)元素!!
检查(索引=0)
@抑制(“未选中的_CAST”)
将数组[索引--]返回为E
}
}

谢谢。实际上,拥有一个由可空类型参数参数化的KClass是没有意义的<代码>类型=类(带类型参数)+可空性
。但我实际上认为这是一个bug,因为行
E::class.javaObjectType
产生了错误。操作员
应返回KClass。类型可以为null,也可以不为null,但它总是有一个ClassInterest的想法,在运行时检查是否为null。完全安全)酷!通过使用Kotlin的内联函数,
arrayOfNulls
的调用被所需类型的数组创建所取代。维利(漂亮)谢谢!
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
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
    }
}