@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>() 

Теперь я хотел иметь такое же поведение доступа, как и Kotlin в Java, то есть:

 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); 

Но тем не менее, мне бы очень понравилось, если бы у меня были такие, как в Котлине:

 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, а intialize их как 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 s, и вы можете получить к нему доступ непосредственно с обоих языков, и они будут инициализированы с реальной стоимостью при создании.

Обновить:

Вот более короткая версия (by @ mfulton26 ):

 abstract class Vec2t<T : Number>(@JvmField var x: T, @JvmField var y: T) 

@JvmField инструктирует компилятор Kotlin не генерировать геттеры / сеттеры для этого свойства и выставлять его как поле, поэтому, если это будет поле, его невозможно будет перезаписать.

Для вашего случая вам нужно что-то вроде этого:

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