生成的 setter 与接口方法冲突
Generated setter clashes with an interface method
我正在编写一个 class 实现一个公开 setSelected
方法的接口。这个 class 会有一个 selected
属性:
private class Foo : IFoo {
var selected = false
override fun setSelected(isActive: Boolean) {
selected = isActive
}
}
但是编译器抱怨,因为 Kotlin 为 selected
生成 setter,这两种方法冲突:
Error:(14, 9) Kotlin: [com.bar.jvmTest] Platform declaration clash: The following declarations have the same JVM signature (setSelected(Z)V):
fun <set-selected>(<set-?>: Boolean): Unit defined in foo.bar.baz.Foo
fun setSelected(isActive: Boolean): Unit defined in foo.bar.baz.Foo
Error:(24, 9) Kotlin: [com.bar.jvmTest] Platform declaration clash: The following declarations have the same JVM signature (setSelected(Z)V):
fun <set-selected>(<set-?>: Boolean): Unit defined in foo.bar.baz.Foo
fun setSelected(isActive: Boolean): Unit defined in foo.bar.baz.Foo
我很想删除自定义方法以利用 setter,但是它没有标记 override
,所以我的 class 没有完全实现接口:
Error:(11, 13) Kotlin: [com.bar.jvmTest] Class 'Foo' is not abstract and does not implement abstract member public abstract fun setSelected(isActive: Boolean): Unit defined in bar.baz
我知道我可以将 selected
重命名为例如dataSelected
以便生成的 setter 不会与方法冲突,但应该有一种方法来保持这个简单的 属性 名称 和 实现界面如预期。
有没有办法让 Kotlin 编译器不为这个 属性 生成 setter,或者将其标记为 override
?
您可以创建一个没有支持字段的 属性,然后像这样覆盖您的抽象函数:
class Foo : IFoo {
private var hiddenSelected = false
val selected get() = hiddenSelected
override fun setSelected(isActive: Boolean) {
hiddenSelected = isActive
}
}
更新:
睡了一觉之后,我觉得这个解决方案一点也不好,原因有两个:
- 它引入了一个不需要的新字段(
hiddenSelected
)
- 您不能使用标准的 Kotlin 方式(
=
运算符)对该字段进行赋值
我认为最好的解决方案是:
class Foo : IFoo {
@set:JvmName("setSelected0")
var selected: Boolean = false
set(value) { setSelected(value) }
override fun setSelected(isActive: Boolean) {
// Possibly some other stuff
println("Now i'm using my own setter!")
selected = isActive
}
}
使用注释 @JvmName 你可以告诉编译器如何命名那个特定的函数。 Kotlin 会自动为每个 属性 创建一个 getter 和 setter,所以你需要使用 set:
修饰符来注释那个 属性 的 setter而不是 属性 本身。
此外,为 属性 实现自定义 setter 也很重要,这样您就可以 安全地 编写:
Foo().selected = true // This also prints "Now i'm using my own setter!"
而不是这个:
Foo().setSelected(true)
您的 setter 可能会做一些其他事情(例如打印该日志),这可能会产生副作用,因此您需要确保调用正确的 setter。这有时会有点棘手,因为 Kotlin 总是为每个可变变量 (var
) 创建一个 setter。
你可以use @JvmName
to rename the generated setter:
private class Foo : IFoo {
@set:JvmName("setSelected0")
var selected = false
override fun setSelected(isActive: Boolean) {
selected = isActive
}
}
Kotlin 的使用保持不变。
我正在编写一个 class 实现一个公开 setSelected
方法的接口。这个 class 会有一个 selected
属性:
private class Foo : IFoo {
var selected = false
override fun setSelected(isActive: Boolean) {
selected = isActive
}
}
但是编译器抱怨,因为 Kotlin 为 selected
生成 setter,这两种方法冲突:
Error:(14, 9) Kotlin: [com.bar.jvmTest] Platform declaration clash: The following declarations have the same JVM signature (setSelected(Z)V):
fun <set-selected>(<set-?>: Boolean): Unit defined in foo.bar.baz.Foo
fun setSelected(isActive: Boolean): Unit defined in foo.bar.baz.Foo
Error:(24, 9) Kotlin: [com.bar.jvmTest] Platform declaration clash: The following declarations have the same JVM signature (setSelected(Z)V):
fun <set-selected>(<set-?>: Boolean): Unit defined in foo.bar.baz.Foo
fun setSelected(isActive: Boolean): Unit defined in foo.bar.baz.Foo
override
,所以我的 class 没有完全实现接口:
Error:(11, 13) Kotlin: [com.bar.jvmTest] Class 'Foo' is not abstract and does not implement abstract member public abstract fun setSelected(isActive: Boolean): Unit defined in bar.baz
selected
重命名为例如dataSelected
以便生成的 setter 不会与方法冲突,但应该有一种方法来保持这个简单的 属性 名称 和 实现界面如预期。
有没有办法让 Kotlin 编译器不为这个 属性 生成 setter,或者将其标记为 override
?
您可以创建一个没有支持字段的 属性,然后像这样覆盖您的抽象函数:
class Foo : IFoo {
private var hiddenSelected = false
val selected get() = hiddenSelected
override fun setSelected(isActive: Boolean) {
hiddenSelected = isActive
}
}
更新:
睡了一觉之后,我觉得这个解决方案一点也不好,原因有两个:
- 它引入了一个不需要的新字段(
hiddenSelected
) - 您不能使用标准的 Kotlin 方式(
=
运算符)对该字段进行赋值
我认为最好的解决方案是:
class Foo : IFoo {
@set:JvmName("setSelected0")
var selected: Boolean = false
set(value) { setSelected(value) }
override fun setSelected(isActive: Boolean) {
// Possibly some other stuff
println("Now i'm using my own setter!")
selected = isActive
}
}
使用注释 @JvmName 你可以告诉编译器如何命名那个特定的函数。 Kotlin 会自动为每个 属性 创建一个 getter 和 setter,所以你需要使用 set:
修饰符来注释那个 属性 的 setter而不是 属性 本身。
此外,为 属性 实现自定义 setter 也很重要,这样您就可以 安全地 编写:
Foo().selected = true // This also prints "Now i'm using my own setter!"
而不是这个:
Foo().setSelected(true)
您的 setter 可能会做一些其他事情(例如打印该日志),这可能会产生副作用,因此您需要确保调用正确的 setter。这有时会有点棘手,因为 Kotlin 总是为每个可变变量 (var
) 创建一个 setter。
你可以use @JvmName
to rename the generated setter:
private class Foo : IFoo {
@set:JvmName("setSelected0")
var selected = false
override fun setSelected(isActive: Boolean) {
selected = isActive
}
}
Kotlin 的使用保持不变。