Kotlin接口中的伴生对象

35

我试图让一个接口可被序列化,所以我需要像这样的一个接口:

interface AB : Parcelable {
    companion object {
        val CREATOR : Parcelable.Creator<AB>
    }
}

我的两个类A和B长得像:

data class A (...): Parcelable{
    ...
    companion object {
        val CREATOR : Parcelable.Creator<AB> = object : Parcelable.Creator<AB> {
            override fun newArray(size: Int): Array<AB?> {
                return arrayOfNulls(size)
            }

            override fun createFromParcel(parcel: Parcel): AB {
                return A(parcel)
            }

        }
    }

我在尝试在Kotlin中实现这样的接口,但似乎接口类不允许使用CREATOR。

也许我的方法不正确, 我有一个包含A或B类列表的可包含对象, 所以我正在做如下操作:

parcel.readTypedList(this.list, AB.CREATOR)

我需要列表必须是A或B,这就是为什么我使用接口的原因。

有没有人有建议或可能的解决方案?


如果您遇到特定的编译错误,请发布该错误。 - Doug Stevenson
谢谢大家的帮助,我觉得我没有很好地描述我的问题。无论如何,我通过遵循这个答案 https://dev59.com/2WEh5IYBdhLWcg3wTB1c 并将Java重写为Kotlin来解决它。效果很好,只是我不再使用数据类了。我尝试过ParcelPaper,但它对我没用。 - mickstar
2个回答

57
在 Kotlin 中,接口可以拥有一个 伴生对象,但它不是必须由实现该接口的类来实现的契约的一部分。它只是与接口相关联的对象,具有一个单例实例。因此,它是一个可以存储东西的地方,但对于实现类并没有任何意义。
然而,您可以有一个由类的 伴生对象 实现的接口。也许您想要更像这样的东西:
interface Behavior {
   fun makeName(): String
}

data class MyData(val data: String) {
    companion object: Behavior {  // interface used here
        override fun makeName(): String = "Fred"
    }
}

请注意,数据类不实现接口,但它的伴生对象实现了接口。
接口上的“伴生对象”可用于存储与接口相关的常量或辅助函数,例如:
interface Redirector {
    fun redirectView(newView: String, redirectCode: Int)

    companion object {
        val REDIRECT_WITH_FOCUS = 5
        val REDIRECT_SILENT = 1
    }
}

// which then can be accessed as:
val code = Redirector.REDIRECT_WITH_FOCUS

6
过去,允许使用通用约束条件,例如“任何一个实现Xyz的伴生对象的类”,这在早期的Kotlin中消失了,但希望将来以另一种类型的通用约束条件重新出现。这样,您就可以通用地谈论一个类及其伴生对象。 - Jayson Minard
这在 Kotlin 中仍然是 4/13/17 的情况吗? - Adam Hughes
@AdamHughes 您是指包括伴生对象的通用约束吗?如果是,我认为它们尚未恢复。 - Jayson Minard
Jayson,我指的是将伴生对象放入接口中,就像你在这个答案的最后代码片段中展示的那样。 - Adam Hughes

10

通过约定,实现Parcelable接口的类也必须有一个非空的静态字段,名称为CREATOR,类型为实现了Parcelable.Creator接口的类型。

需要使用@JvmField注解来为CREATOR属性添加注释,以将其公开为包含数据类中的公共静态字段。

您还可以查看https://github.com/grandstaish/paperparcel——这是一个注解处理器,可自动生成适用于Kotlin和Java的类型安全的Parcelable包装器。


我认为你的回答的第一部分并没有帮助。第二部分本身就很有用。 - Jayson Minard
@JaysonMinard 在这种情况下需要遵循Parcelable的约定,我编辑了答案来解释原因。 - Ilya
非常感谢,它也需要是 JvmStatic 吗?或者在伴生对象中使用 JvmField 也可以吗? - Jayson Minard
@JaysonMinard 不是的,JvmStatic 是用于方法的。这在最近的文档中已经得到了解决:https://kotlinlang.org/docs/reference/java-to-kotlin-interop.html#static-methods - Ilya
@JvmField在接口的伴生对象中似乎无效。对此有何想法? - dumptruckman

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接