Конечные переменные Scala в конструкторе - PullRequest
5 голосов
/ 02 октября 2011

Я все еще довольно новичок в Scala, но я знаю, что вы можете определить переменные класса, которые инициализируются в конструкторе, например

class AClass(aVal: String)

что будет похоже на выполнение следующих действий в Java

class AClass {
    private String aVal;

    public AClass(String aVal) {
        this.aVal = aVal;
    }
}

В Java я бы объявил aVal как окончательный. Есть ли способ сделать финальную переменную aVal в синтаксисе Scala?

РЕДАКТИРОВАТЬ: Вот что я вижу, когда я компилирую следующий класс Scala:

class AClass(aVal: String) {
  def printVal() {
    println(aVal)
  }
}

Я запустил javap -private и получил вывод

public class AClass extends java.lang.Object implements scala.ScalaObject{
  private final java.lang.String aVal;
  public void printVal();
  public AClass(java.lang.String);
}

Когда я изменяю определение класса scala на class AClass(**val** aVal: String), я получаю следующий вывод из javap -private

public class AClass extends java.lang.Object implements scala.ScalaObject{
  private final java.lang.String aVal;
  public java.lang.String aVal();
  public void printVal();
  public AClass(java.lang.String);
}

Публичный метод aVal генерируется. Я все еще учусь здесь - кто-нибудь может объяснить, почему это генерируется?

Обратите внимание, я использую scala 2.9

Ответы [ 2 ]

10 голосов
/ 02 октября 2011
class AClass(aVal: String)

В этом коде aVal является конечной переменной.Итак, у вас уже есть конечная переменная.

class AClass(val aVal: String)

В этом коде aVal является окончательным, и у вас есть получатель aVAl.Таким образом, вы можете использовать его, как показано ниже

scala> val a= new AClass("aa")
a: A1 = A1@1d7d58f

scala> a.aVal
res2: String = aa

И, наконец,

class AClass(var aVal: String)

В этом коде aVal не является окончательным, и у вас есть метод получения и установки aVal.Таким образом, вы можете использовать его, как показано ниже

scala> val a= new AClass("aa")
a: AClass = AClass@1c059f6

scala> a.aVal
res3: String = aa

scala> a.aVal = "bb"
a.aVal: String = bb

scala> a.aVal
res4: String = bb
8 голосов
/ 02 октября 2011

Скопировано из моего ответа: Окончательный Scala и Val для видимости параллелизма

Есть два значения термина final: a) для полей / методов Scala и методов Java это означает«не может быть переопределено в подклассе» и б) для полей Java, а в байт-коде JVM это означает «поле должно быть инициализировано в конструкторе и не может быть переназначено».

Параметры класса, отмеченные val (илиэквивалентно, параметры класса case без модификатора) действительно являются окончательными во втором смысле и, следовательно, потокобезопасны.

Вот доказательство:

scala>  class A(val a: Any); class B(final val b: Any); class C(var c: Any)
defined class A
defined class B
defined class C

scala> import java.lang.reflect._
import java.lang.reflect._

scala> def isFinal(cls: Class[_], fieldName: String) = {
     |   val f = cls.getDeclaredFields.find(_.getName == fieldName).get
     |   val mods = f.getModifiers
     |   Modifier.isFinal(mods)
     | }
isFinal: (cls: Class[_], fieldName: String)Boolean

scala> isFinal(classOf[A], "a")
res32: Boolean = true

scala> isFinal(classOf[B], "b")
res33: Boolean = true

scala> isFinal(classOf[C], "c")
res34: Boolean = false

Или с javap, что может быть удобнозапустить из REPL:

scala> class A(val a: Any)
defined class A

scala> :javap -private A
Compiled from "<console>"
public class A extends java.lang.Object implements scala.ScalaObject{
    private final java.lang.Object a;
    public java.lang.Object a();
    public A(java.lang.Object);
}

Если параметр класса не-case класса не помечен как val или var, и на него не ссылаются никакие методы, ему нужно толькобыть видимым для конструктора класса.Компилятор Scala может свободно оптимизировать поле вне байт-кода.В Scala 2.9.1 это работает:

scala> class A(a: Any)
defined class A

scala> :javap -private A
Compiled from "<console>"
public class A extends java.lang.Object implements scala.ScalaObject{
    public A(java.lang.Object);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...