@JvmField属性的泛型/抽象类

目前我有一个抽象类 :

abstract class Vec2t<T : Number> { abstract var x: T abstract var y: T ... } 

还有很多实施的,比如这个 :

 data class Vec2(override var x: Float, override var y: Float) : Vec2t<Float>() 

现在,我的愿望是具有与Java中的Kotlin相同的访问行为,即:

 val f = vx 

要么

 vx = f 

但是从Java当然默认是:

 float f = v.getX(); 

要么

 v.setX(f); 

我通过编写特定的访问功能减少了某种“压力”:

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

所以我可以“只”:

 float f = vx(); 

要么

 vx(f); 

但是,如果我能像Kotlin一样拥有这些东西,

 float f = vx; 

要么

 vx = 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只能应用于最终的属性

有没有机会让我不知道?

由于@JvmField是直接用Java访问的,所以我们不能像委托那样使用任何微妙的东西进行初始化,也不能将它标记为lateinit 。 这也是为什么它不能得到抽象的或开放的财产的支持; 如果你有float x; 在Java中的一个类中,它直接被访问,并且不能以任何方式拦截它的读/写,而所有上述特性都需要。

您正在尝试解决的问题是在创建时使用有效的值初始化它们。 你可以做的一件事是把它们标记为空,并将它们初始化为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) 

@JvmField指示Kotlin编译器不要为这个属性生成getters / setter,并将它作为一个字段公开,所以如果它是一个字段,将不能覆盖它。

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

 abstract class Vec2t<T : Number> { @JvmField var x: T @JvmField var y: T }