@JvmField关于泛型/抽象类的属性

时间:2017-03-07 10:57:35

标签: kotlin

目前我有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);

我以某种方式减少了压力&#34;通过编写具体的access funtions

fun x(x: T) {
    this.x = x
}
fun y(y: T) {
    this.y = y
}

所以我只能&#34;

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无法应用于委托属性

如果我尝试初始化它:

    @JvmField open var x = 0 as T
  

@JvmField只能应用于最终属性

我有机会不知道吗?

2 个答案:

答案 0 :(得分:2)

由于在Java中直接访问@JvmField,我们无法像委托那样使用任何棘手的东西进行初始化,也不能将其标记为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)

答案 1 :(得分:-1)

@JvmField指示Kotlin编译器不为此属性生成getter / setter并将其作为字段公开,因此如果它是一个字段,则无法覆盖它。

对于你的情况,你需要这样的东西:

CountRequestBuilder