Scala final против val для одновременного просмотра - PullRequest
28 голосов
/ 02 октября 2011

В Java, при использовании объекта в нескольких потоках (и в целом), рекомендуется сделать поля окончательными.Например,

public class ShareMe {
    private final MyObject obj;
    public ShareMe(MyObject obj) {
        this.obj = obj;
    }
}

В этом случае видимость obj будет одинаковой для нескольких потоков (предположим, что obj также имеет все конечные поля), поскольку он безопасно создан с использованием ключевого слова final.

В scala это не похоже на то, что val компилируется до окончательной ссылки, скорее, val - это семантика в scala, которая не позволяет переназначить переменную ( Окончательные переменные Scala в конструкторе ).Если переменные конструктора scala не определены как final, будут ли они страдать от той же проблемы (при использовании этих объектов в акторах)?

Ответы [ 2 ]

49 голосов
/ 02 октября 2011

Ответ на другой вопрос вводит в заблуждение. Существует два значения термина final: а) для полей / методов 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);
}
1 голос
/ 02 октября 2011

Думаю, я неправильно понял, как компилируется var. Я создал образец класса

class AVarTest(name:String) {
   def printName() {
     println(name)
   }
}

Я бежал javap -private, и это привело к

public class AVarTest extends java.lang.Object implements scala.ScalaObject{
    private final java.lang.String name;
    public void printName();
    public AVarTest(java.lang.String);
}

И имя фактически скомпилировано в финал.

Это также показано в Scala val должен быть защищен синхронизированными для одновременного доступа?

...