Kotlin实体types参数不能作为函数体中的types参数
Kotlin中的特定types参数可防止types参数擦除,并允许在运行时知道types参数。 这允许以下代码编译并按预期方式运行:
inline fun isA(value: Any) = value is T
但是,当我尝试使用“T”作为types参数而不是独立时,我得到一个消息,它是一个擦除types。 以下代码仅供说明用途 :
inline fun isListOfA(name: String): Boolean { val candidate = Class.forName(name) return candidate is List }
这是由于技术限制吗? 如果是这样,那么这个限制是什么?
JVM上防止你做的是generics擦除的技术限制。 基本上,在运行时,genericstypesList
的对象变成了一个与对象一起工作的List
:它只在编译时才会检查types安全性以用于赋值和函数调用。 实际的types参数T
只在编译期间存在,然后被擦除。 它不能在运行时恢复(至少现在是:有一个Project Valhalla可能会为JVM引入运行时实现generics)。
在一个非内联的Kotlin函数中(和一个非特定types的参数),你甚至不能做第一种检查, value is T
,因为一个普通的types参数也会被擦除。
使用具体化的types参数,函数体在其调用位置获取内联,实际(或推断)的types参数替换为T
:当调用isA
,调用站点将具有字节码instanceof
检查String
。
但即使使用了具体的types参数,也不能反思generics:你可以检查something is List<*>
是something is List
但不是something is List
:type参数不存储在运行时的任何地方。
另请注意, isA
将返回>(listOf(1, 2, 3))
true
。 这就是在Kotlin中处理这种奇怪的情况:只有types的非generics部分可以在运行时被实际检查,事实上也是如此。
因为Java在编译时将genericstypes参数T
擦除为Object
/ upper-boundtypes,所以在Kotlin中没有办法做到这一点。
第一种方法可以工作,因为value is T
被内联到具体化types的call-site函数中,例如:
//val is_string = isA(1) // inline into the call-site function as below: val i:Int = 1 // v--- the actual type argument is inlined here val is_string = 1 is String
参数化types总是在运行时擦除。 所以你可以检查一个值是一个T
实例,而不是一个T
实例,不管T
和V
是被赋值还是硬编码的。
然而,即使这是可能的,你的示例代码没有意义,因为它检查具有该名称的types是否是List 实例 ,而不是检查具有该名称的types是否是期望的Listtypes。
如果你有一个对象的实例 ,并且想要检查它是一个只包含预期types的List的List,那么你仍然可以这样写:
inline fun isListOfA(instance: Any) = instance is List<*> && instance.all { it is T }
显然我没有适当地提出我的问题来得到我想要的forms的答案。 这里的大部分答案都是“因为你不能用Java来做”的一些变化。 那么,你不能在Java中使用x instanceof T
,但是你可以在Kotlin中做x is T
。 我正在寻找不是Java规则的潜在实际障碍。 毕竟,规则是被打破的。
从我对这里的第一个答案的评论中,重新提出的问题是:如果objectref is T
可以通过某种机制在Kotlin中工作X
为什么不能通过同一个机制使objectref is SomeClass
工作?
tl; dr回答:因为在运行时SomeClass
不会有Class
对象。
较长的答案:首先我们必须理解机制X
,它是is T
生成一个字节码指令的instanceof
。 该指令采用objectref
和某个C
类的名称N
,其中N
由编译器根据上下文确定。 在运行时,从N
派生的类C
将被用来评估objectref is T
expression式。 为了进行评估, C
的类对象必须被实例化。 所以要使用objectref is SomeClass
机制objectref is SomeClass
那么N
就是SomeClass
。 由于types擦除, SomeClass
将不会有类对象,因此不可能生成所需的instanceof
指令,从而应用相同的机制。 另外, instanceof
指令不能采用SomeClass
forms的名称。 因此,如果objectref is SomeClass
是要工作的,那么其他一些机制Y
必须在Kotlin中find并实现。 这种机制可能存在也可能不存在。
我知道有些人可能会说这和其他一些答案是一样的。 然而,无论好坏,我的学习风格都是要理解事物在金属上的运作方式,然后将其与抽象模型进行综合。 在这种情况下,Javagenerics删除的概念是抽象模型(或其一部分)。 真的,“删除”对我来说会觉得很卑鄙,除非我至少明白在实施过程中实现的一种方式。