覆盖Kotlin中的吸气剂?

CLO*_*VIS 0 kotlin

因此,我有一个抽象类Composition,它有两个孩子:一个是Track,一个是Album(专辑是一组Track)。

class Composition(val name: String, ...)
class Track(name: String): Composition(name)
class Album(name: String, val tracks: List<Track>): Composition(name)
Run Code Online (Sandbox Code Playgroud)

到目前为止,一切都很好。现在,我添加了持续时间。它在Composition中是抽象的,因此我可以在子级中覆盖它:

abstract class Composition(...){
    abstract fun getDuration(): Int
}
Run Code Online (Sandbox Code Playgroud)

现在,我可以在Track中添加覆盖方法,该方法将其作为参数:

class Track(..., private val duration: Int): Composition(...){
    override fun getDuration() = duration
}
Run Code Online (Sandbox Code Playgroud)

最后,我制作了专辑,其持续时间是Tracks的总和:

class Album(..., val tracks: List<Track>): Composition(...){
    override fun getDuration() = tracks.sumBy { it.getDuration() }
}
Run Code Online (Sandbox Code Playgroud)

它可以按预期工作,但是我不明白为什么不能简单地使用tracks.sumBy { it.duration },因为在Kotlin中,属性不过是getter和setter(我在考虑getDurationin Composition)。

我感觉好像丢失了一些东西,因为如果用Java编写相同的代码,则可以将其composition.duration作为属性调用-因此,我认为Kotlin允许Java代码提供它,但Kotlin代码不允许难过。

另一个例子:

假设我有一个名为的类Artist,它编写了多个Compositions:

class Artist(
    val nom: String,
    private val _compositions: MutableList<Composition> = ArrayList()
) {

    // HERE (I wrote the extension method List<E>.toImmutableList)
    fun getCompositions() : List<Composition> = _compositions.toImmutableList()
}
Run Code Online (Sandbox Code Playgroud)

这是Java中的标准(通过getter公开Collections的不可变版本,因此它们不会被修改);Kotlin不能识别它:

val artist = Artist("Mozart")
artist.getCompositions() // Legal
artist.compositions      // Illegal
Run Code Online (Sandbox Code Playgroud)

我曾考虑过将其设置为属性,但是:-如果选择type List<E>,则可以覆盖getter以返回不可变列表,但add由于Listis是不可变的,因此无法使用常规方法(...)-如果选择type MutableList<E>,我无法覆盖getter以返回ImmutableList(这是List我编写的子类,并且显然不是的子类MutableList)。

有一个简单的解决方案时,我可能会做一些荒谬的事情,但是现在我找不到它。

最后,我的问题是:从Kotlin编写时,为什么不将手动编写的getter视为属性?

而且,如果我记错了,解决这两种模式的预期方法是什么?

Ren*_*ene 5

您必须将持续时间定义为抽象属性,而不是抽象函数(https://kotlinlang.org/docs/reference/properties.html#getters-and-setters):

abstract class Composition(val name: String) {
    abstract val duration: Int
}
class Track(name: String, override val duration: Int): Composition(name)
class Album(name: String, val tracks: List<Track>): Composition(name) {
    override val duration: Int
        get() = tracks.sumBy { it.duration }
}
Run Code Online (Sandbox Code Playgroud)

将getter / setter转换为属性仅适用于Java类(https://kotlinlang.org/docs/reference/java-interop.html#getters-and-setters)。


osi*_*pxd 5

如果要将其用作属性,则应使用Kotlin-way覆盖getter。
例如:

abstract class Composition(...){
    abstract val duration: Int
}

// You can use "override" in constructor
// val - is immutable property that has only getter so you can just 
// remove private modifier to make possible get it.
class Track(..., override val duration: Int): Composition(...){
    ...
}

class Album(..., val tracks: List<Track>): Composition(...) {
    override val duration: Int 
        get() = tracks.sumBy { it.duration }
}
Run Code Online (Sandbox Code Playgroud)

当您需要仅在对象内部可以更改的可变属性时,可能还会出现这种情况。在这种情况下,您可以使用私有设置器声明可变属性:

class SomeClass(value: Int) {
    var value: Int = value
        private set
}
Run Code Online (Sandbox Code Playgroud)

在文档中阅读更多信息:https : //kotlinlang.org/docs/reference/properties.html#getters-and-setters