В 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, будут ли они иметь ту же проблему (при использовании этих объектов в акторах)?
Ответ на другой вопрос вводит в заблуждение. Есть два значения термина 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);
}