目前,我有一个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/

10-10 08:23