Scala final vs val для видимости параллелизма

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

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

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

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

28
задан Community 23 May 2017 в 11:54
поделиться

1 ответ

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

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

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

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);
}
50
ответ дан 28 November 2019 в 03:13
поделиться
Другие вопросы по тегам:

Похожие вопросы: