Kotlin:is检查为何需星投影?Dog<*>与Any?的差异解析
Kotlin泛型is检查中星投影的使用原因
先看你提供的代码(修正了Str为Kotlin合法的String):
class Dog<T: Comparable<T>>(private val name: String, private val weight: T): Comparable<Dog<T>> { override fun compareTo(other: Dog<T>): Int { return weight.compareTo(other.weight) } override fun equals(other: Any?): Boolean { if (other == null || other !is Dog<*>) return false return name == other.name && weight == other.weight } }
你提到的核心问题:为什么equals里的is检查能用Dog<*>,却不能用Dog<Any?>?原因主要有三点:
1. 星投影与具体类型参数的本质区别
Dog<*>是星投影,它代表「任意合法类型参数的Dog实例」——不管这个Dog对象创建时用的是什么类型参数(只要符合T: Comparable<T>的约束),is Dog<*>都会判定为true。这正好满足equals的需求:我们只需要确认对方是Dog类的实例,不需要关心它的类型参数具体是什么。Dog<Any?>则是指定了具体类型参数的泛型类型,它仅代表「类型参数为Any?的Dog实例」。但你的Dog类要求类型参数T必须实现Comparable<T>,而Any?并没有实现这个接口,所以实际上不存在合法的Dog<Any?>实例,编译器直接会拒绝把它用于is检查。
2. 类型擦除的影响
Kotlin的泛型是基于类型擦除实现的,运行时无法获取对象的具体泛型类型参数。星投影的设计就是为了应对这种场景:当你不需要关心泛型的具体类型参数,只需要判断是否为某个泛型类的实例时,用星投影就能绕过类型参数的具体校验,匹配所有该泛型类的实例。
而如果用Dog<Any?>这种具体类型参数的写法,编译器会先校验该类型参数是否符合泛型类的约束——显然Any?不满足T: Comparable<T>,所以直接报错,根本到不了运行时检查的阶段。
3. 逻辑合理性
在equals方法中,我们需要判断的是两个对象是否属于同一类(这里是Dog类),而不是「是否属于类型参数为某特定值的Dog类」。星投影正好贴合这个逻辑,而指定具体类型参数反而会缩小匹配范围,甚至因为约束不合法而无法使用。
内容的提问来源于stack exchange,提问作者ntos
相关产品推荐
相关产品推荐

