Kotlin中判断sealed class对象同类型及object作为Map key取值null问题
问题根因分析
Kotlin中object声明的类默认是JVM单例的前提是由同一个类加载器加载,且没有经过序列化/反序列化、反射强制构造等操作。你遇到的多实例场景,大概率是不同模块使用了独立的类加载器加载SealedClass类,或者Pizza对象经历了序列化/反序列化流程,才生成了多个不同引用的实例。默认object的equals方法是引用相等判断,所以两个不同实例作为Map的key时会被判定为不同键,导致取值返回null。
实现Pizza实例作为key可统一取值的方案
方案1:单独给Pizza重写equals和hashcode(轻量改法)
如果你不想修改父类和其他子类的原有逻辑,直接给Pizza单例单独重写相等判断规则即可:
sealed class SealedClass { object Pizza: SealedClass() { override fun equals(other: Any?): Boolean { return other is Pizza } override fun hashCode(): Int { return this::class.hashCode() } } data class Hamburger(val hasCheese: Boolean): SealedClass() }
修改后只要是Pizza类型的实例,不管引用是否相同,都会被判定为相等,作为Map的key可以正常取值,Hamburger作为data class默认的属性相等判断逻辑不受影响。
方案2:统一重写父类的equals和hashcode(推荐)
如果后续还要新增sealed类的子类,可以统一在父类中定义相等规则,避免后续重复修改:
sealed class SealedClass { object Pizza: SealedClass() data class Hamburger(val hasCheese: Boolean): SealedClass() override fun equals(other: Any?): Boolean { if (this === other) return true if (javaClass != other?.javaClass) return false return when (this) { is Pizza -> true is Hamburger -> hasCheese == (other as Hamburger).hasCheese } } override fun hashCode(): Int { return when (this) { is Pizza -> javaClass.hashCode() is Hamburger -> 31 * javaClass.hashCode() + hasCheese.hashCode() } } }
方案3:从根源避免生成多实例
如果是序列化导致的多实例问题,可以给Pizza单例添加readResolve方法,反序列化时强制返回全局单例:
object Pizza: SealedClass() { private fun readResolve(): Any = Pizza }
如果是类加载器导致的问题,调整模块的类加载策略,保证SealedClass由同一个类加载器加载即可。
两个sealed class对象的同类型判断方法
- 同类加载器场景:直接比较
::class属性即可,示例:obj1::class == obj2::class - 跨类加载器场景:比较类的全限定名,示例:
obj1.javaClass.name == obj2.javaClass.name - 单一类型判断:直接使用
is关键字,示例:if (obj is SealedClass.Pizza) { /* 是Pizza类型 */ }
内容的提问来源于stack exchange,提问作者mooglin
相关产品推荐
相关产品推荐

