На данный момент у меня есть абстрактный класс :
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 }