首页 文章

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

提问于
浏览
5

我正在将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 :

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 回答

  • 3

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

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

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

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

  • 0

    主要问题是类型 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
    

    但是,您可以使用 subset typesubtype 覆盖 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是一个零安全系统,即使属性是 nullable 属性,也无法在不初始化的情况下定义属性:

    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

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

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

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

相关问题