在kotlin中使用Interface时获取平台声明冲突

我将Java中的一些类转换为kotlin,并且在尝试从接口继承时遇到编译错误:

平台声明冲突:以下声明具有相同的JVM签名(getContentID()Ljava / lang / String;):

公开开放的乐趣get-content-id():String? public open fun getContentId():String?

这里是界面:

interface Media { val contentId: String val displayRunTime: String val genres: List<String> val programId: String val runTime: String val type: String } 

这里是班级:

 class Airing : Media { override val contentId: String? = null override val displayRunTime: String? = null override val genres: List<String>? = null override val programId: String? = null override val runTime: String? = null override val type: String? = null override fun getContentId(): String? { return contentId } 

我是kotlin的超级新手。

你不需要声明override fun getContentId(): String? ,因为Media接口的val contentId: String已经被override val contentId: String?覆盖了override val contentId: String?

您得到的错误意味着您声明的函数与已为contentId属性(getter具有相同签名)生成的getter在JVM字节码中发生冲突。

在Kotlin中,您应该直接使用属性contentId ,而在Java中,您可以使用生成的访问器getContentId()setContentId(...)

另外,Kotlin不允许你用可为空的String?覆盖非空的String属性String? 一个,因为基本接口的用户会期望属性的非空值。 你应该用String替换重写的属性类型,或者使它们成为String? 在界面中。

主要问题是T?T? 包括Tnull 。 反过来, TT的一个子集T? 。 所以你不能用超集类型覆盖T属性,例如:

 interface Source { val content: Any } // v--- ERROR: `Any?` is not a subtype of `Any` class Image(override val content:Any?) : Source 

但是,你可以重写T? 属性及其子类型子类型 ,例如:

 interface Source { val content: Any? } // v--- `Any` is a subset of `Any?` class Image(override val content:Any) : Source // `String` is a subtype of `Any` & `Any?` includes `Any` // v class Text(override val content:String) : Source 

那么你的代码应该如下。 但是,Kotlin是一个空安全系统,即使属性是可以为空的属性,也不能定义一个属性而不初始化它:

 class Airing : Media { // v--- ERROR: the property isn't initialized override val contentId: String ... } 

您应该在主构造函数中引入属性,让客户端代码在将来进行初始化,例如:

 class Airing constructor( override val contentId: String, override val displayRunTime: String, override val genres: List<String>, override val programId: String, override val runTime: String, override val type: String ) : Media 

您也可以为属性提供一些默认值,例如:

 class Airing : Media { override val contentId: String = "<default>" override val displayRunTime: String = "<default>" override val genres: List<String> = emptyList() override val programId: String = "<default>" override val runTime: String = "<default>" override val type: String = "<default>" } 

getContentId函数会和getter冲突,所以你应该删除它。

声明为val的变量就像Java final变量一样,是不可变的,所以你不能设置为Optional ?

你的变量声明应该如下所示:

 interface Media { var contentId: String? //... }