实现Java接口的Kotlin数据类

36

我想在当前项目中引入Kotlin。我决定从实体开始,这似乎完美地映射到数据类。 例如,我有一个数据类:

data class Video(val id: Long, val ownerId: Long, val title: String, val description: String? = null,
             val imgLink: String? = null, val created: Date? = null, val accessKey: String? = null,
             val views: Long? = null, val comments: Long? = null, val videoLink: String? = null): Entity

实现了Java接口:

public interface Entity {
   Long getId();  
}

但出于某种原因,编译器无法理解该方法已经被实现:

类“Video”必须声明为抽象或实现抽象成员public abstract fun getId(): kotlin.Long! defined in net.alfad.data.Entity

我是否需要为id参数使用任何其他关键字? 签名中的“!”代表什么意思?


1
在签名中的!表示这是一个平台类型,即来自Java的类型。您可以在文档中了解更多相关信息。 - Alexander Udalov
2个回答

54
问题在于 Kotlin 优先加载 Java 类 Entity,因此它将 getId 视为一个函数,而不是某个属性的 getter。Kotlin 类中的属性 getter 无法覆盖函数,因此属性 id 不能作为 getId 函数的实现绑定。
为了解决这个问题,您应该在 Kotlin 类中重写原始函数 getId。这样做会导致您的新函数和 id 的 getter 在字节码中产生 JVM 签名冲突,因此您还应该通过使属性 private 来防止编译器生成 getter:
data class Video(
    private val id: Long,
    ...
): Entity {
    override fun getId() = id

    ...
}

请注意,此答案已从此处进行了改编:https://dev59.com/Y1wY5IYBdhLWcg3wH01C#32971284


不错的答案!还有一个问题:这是否意味着getter/setter不像Java中的常规方法? - Odysseus
2
在生成的字节码中,从Java的角度来看,它们是相同的。属性 getter 被编译成名为 getXxx 的方法。但对于 Kotlin(版本1.0.0),属性访问器和函数是不同的,您不能在层次结构中混合使用这两个概念。 - Alexander Udalov
有关于更改这个的讨论吗?有没有理由它不能正常工作? - Christian Bongiorno
1
这里有一个问题。其中一个问题是,在 Kotlin 中,您无法通过 fun getX 或反之覆盖 val x(按设计),因此如果您在 Kotlin 和 Java 代码的混合层次结构中具有一些类使用属性和一些类使用函数,则会出现各种复杂的问题。 - Alexander Udalov
根据这个答案,我认为将接口也移植到 Kotlin 中会解决这个问题,但实际上并没有,这是因为字节码仍然像 Java 类一样创建,因为我仍然在一个混合项目中吗? - avalancha
@avalancha 将接口转换为 Kotlin 并将 get 方法更改为属性 (fun getX -> val x) 可以解决这个问题。 - Alexander Udalov

1
如果这是你的整个数据类,那么你没有覆盖 getId()。我看到你有一个名为 id 的属性,Kotlin 应该为其生成一个 getter,但这不会被标记为 override 关键字,你需要使用 override 关键字来指示你正在覆盖一个抽象函数。
-- 编辑 -- Alexander 比我先回答了!无论如何他的答案更好! ;)

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