Scala getters и seters в классе Java

Я хотел бы создать класс Java, который следует за соглашением Scala seters/getters.

Я пробовал следующий простой класс, но он не работает:

public class JavaA {
private int a = 0;

public int a() {
    return a;
}

public void a_$eq(int a) {
    this.a = a;
}
}

Но когда я пытаюсь получить доступ к нему из scala:

val x = new JavaA
x.a = 1

и я получаю сообщение об ошибке "переназначение в val". Я попытался найти это, но все проблемы, которые я нашел, где другой путь от Scala до java.

Каков правильный способ сделать это?

Спасибо!

Ответ 1

Вы можете только сделать это, и это достаточно сложно, что вы, вероятно, не хотите.

То, что вы не можете сделать, это написать пустой класс Java, который магически интерпретируется как Scala getters и seters. Причина в том, что Scala внедряет информацию в файл класса, который требуется для своих геттеров и сеттеров (например, есть нулевые блоки параметров или один пустой блок параметров - это различие, которое не сохраняется на JVM (или на Java)).

Что вы можете сделать, это использовать Java для реализации интерфейса Scala -defined (т.е. признака):

// GetSetA.scala
trait GetSetA { def a: Int; def a_=(a: Int): Unit }

// JavaUsesGSA.java
public class JavaUsesGSA implements GetSetA {
  private int a = 0;
  public int a() { return a; }
  public void a_$eq(int a) { this.a = a; }
}

То, что вы не можете сделать, тем не менее, использует класс напрямую (опять же, потому что Java не добавляет соответствующую информацию аннотации для Scala):

scala> j.a = 5
<console>:8: error: reassignment to val
       j.a = 5

но поскольку он успешно реализует признак, вы можете использовать его по желанию, когда он набирается как признак:

scala> (j: GetSetA).a = 5
(j: GetSetA).a: Int = 5

Так что это скорее смешанная сумка. Не совершенным никоим образом, но он может быть достаточно функциональным, чтобы помочь в некоторых случаях.

(Другой альтернативой, конечно же, является предоставление неявного преобразования из класса Java в тот, который имеет getter/setter, который ссылается на реальные методы класса Java, это работает, даже если у вас не может быть Java наследуем от Scala.)

(Edit: Конечно, нет никакой критической причины, по которой компилятор должен действовать таким образом, можно утверждать, что интерпретация Java-определенных пар getter/setter, как если бы они были Scala (т.е. если классный файл явно не говорит об этом от Scala) является хорошим кандидатом для улучшения функции для улучшения взаимодействия Java.)

Ответ 2

Я боюсь, что ты не можешь. В Scala аксессор должен быть методом без списка параметров, например def a = _a. Написание, например. def a() = _a в Scala приведет к той же ошибке, и вы не можете определить метод без списка параметров в Java. Возможно, вы сможете обмануть компилятор Scala, создав собственный ScalaSignature, но это, вероятно, не стоит проблем...