目前,我有一个abstract class:
abstract class Vec2t<T : Number> {
abstract var x: T
abstract var y: T
...
}
还有许多实现的方法,例如this one:
data class Vec2(override var x: Float, override var y: Float) : Vec2t<Float>()
现在,我希望具有与Java中的Kotlin相同的访问行为,即:
val f = v.x
要么
v.x = f
但当然从Java出发,默认值为:
float f = v.getX();
要么
v.setX(f);
我通过编写特定的access funtions以某种方式减轻了“压力”:
fun x(x: T) {
this.x = x
}
fun y(y: T) {
this.y = y
}
这样我可以“仅”:
float f = v.x();
要么
v.x(f);
但是,如果我能像Kotlin那样拥有这些东西,我真的很喜欢:
float f = v.x;
要么
v.x = f;
问题是
@JvmField
属性上不允许使用abstract
,但是如果我将Vec2t
切换为:open class Vec2t<T : Number> {
@JvmFiled open var x: T // error
@JvmField open var x by Delegates.notNull<T>()
无效:
如果我尝试初始化它:
@JvmField open var x = 0 as T
我有没有意识到的机会?
最佳答案
由于可以在Java中直接访问@JvmField
,因此我们无法使用诸如委托(delegate)之类的棘手初始化,也无法将其标记为lateinit
。这也是为什么它不能由抽象或开放属性支持的原因。如果您在Java的类中包含float x;
,则可以直接访问它,并且您不能以任何上述所有功能都需要的方式拦截对它的读/写。
您要解决的问题是在创建时使用有效值初始化它们。您可以做的一件事是将它们标记为可为空并将其初始化为null
,但是我认为这将直接与您正在寻找的便利(以及性能(因为现在必须将其装箱))背道而驰。我提到有可能。
这说明您基本上只能使用一种解决方案,或者如果它适合您的用例,建议您从构造函数参数中初始化它们:
abstract class Vec2t<T : Number> constructor(_x: T, _y: T) {
@JvmField
var x: T = _x
@JvmField
var y: T = _y
}
class Vec2(x: Float, y: Float) : Vec2t<Float>(x, y)
这样,您可以将值标记为
@JvmField
,并且可以直接从两种语言访问它,并且在创建时会为其设置真实值。更新:
这是一个简短的版本(由@mfulton26):
abstract class Vec2t<T : Number>(@JvmField var x: T, @JvmField var y: T)
关于kotlin - 通用/抽象类的属性上的@JvmField,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/42646452/