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

时间:2017-08-04 15:13:53

标签: java android kotlin

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

  

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

     

public open fun 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的新手。

3 个答案:

答案 0 :(得分:3)

您不需要声明override fun getContentId(): String?,因为val contentId: String界面中的Media已被override val contentId: String?覆盖。

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

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

此外,Kotlin不允许您使用可为空的String覆盖非空String?属性,因为基接口的用户将期望该属性的非空值。您应该将覆盖的属性类型替换为String,或者在界面中将它们设为String?

答案 1 :(得分:2)

主要问题是T?类型包括Tnull。反过来,TT?的子集。所以你不能用它的超集类型覆盖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>"
}

AND getContentId功能会与getter冲突,因此您应将其删除。

答案 2 :(得分:0)

声明为val的变量与Java final变量类似,是不可变的,因此您无法设置为Optional ?

您的变量声明应如下所示:

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