所以我有一个抽象类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)
到目前为止,太好了。现在,我添加了持续时间。它在组合中是抽象的,因此我可以在子级中覆盖它:
abstract class Composition(...){
abstract fun getDuration(): Int
}
现在,我可以在Track中添加覆盖方法,将其作为参数:
class Track(..., private val duration: Int): Composition(...){
override fun getDuration() = duration
}
最后,我制作了专辑,专辑的持续时间是曲目的总和:
class Album(..., val tracks: List<Track>): Composition(...){
override fun getDuration() = tracks.sumBy { it.getDuration() }
}
它可以按预期工作,但我不明白为什么我不能简单地使用tracks.sumBy { it.duration }
,因为在Kotlin中,属性只不过是吸气剂和吸气剂(我正在考虑{{ 1}})。
我感觉好像丢失了一些东西,因为如果使用Java编写相同的代码,则可以将getDuration
作为属性来调用-因此,我认为Kotlin允许Java代码使用它,但不是来自Kotlin代码,这很可悲。
另一个例子:
假设我有一个名为Composition
的班级,他写了多个composition.duration
:
Artist
这是Java中的标准(通过getter公开Collections的不可变版本,因此它们不会被修改); Kotlin不能识别它:
Composition
我考虑过将其设置为属性,但是:
-如果选择类型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()
}
,则可以覆盖getter以返回不可变列表,但是由于val artist = Artist("Mozart")
artist.getCompositions() // Legal
artist.compositions // Illegal
是不可变的,因此无法使用常规方法(List<E>
...)
-如果选择类型add
,则无法覆盖getter以返回List
(这是我编写的MutableList<E>
的子类,显然不是{{1}的子类}。
虽然有一个简单的解决方案,但我有可能在做一些荒谬的事情,但现在我找不到它。
最后,我的问题是:从Kotlin编写时,为什么不将手动编写的吸气剂视为属性?
而且,如果我记错了,解决这两种模式的预期方法是什么?
答案 0 :(得分:4)
您必须将持续时间定义为抽象属性,而不是抽象函数(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 }
}
作为属性的getter / setter转换仅适用于Java类(https://kotlinlang.org/docs/reference/java-interop.html#getters-and-setters)。
答案 1 :(得分:4)
如果要将其用作属性,则应使用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 }
}
在某些情况下,可能需要仅在对象内部才能更改的可变属性。在这种情况下,您可以使用私有设置器声明可变属性:
class SomeClass(value: Int) {
var value: Int = value
private set
}
在文档中了解更多信息:https://kotlinlang.org/docs/reference/properties.html#getters-and-setters