Scala final vs val dla widoczności współbieżności
W Javie, gdy używa się obiektu w wielu wątkach (i ogólnie), dobrą praktyką jest, aby pola były ostateczne. Na przykład,
public class ShareMe {
private final MyObject obj;
public ShareMe(MyObject obj) {
this.obj = obj;
}
}
W tym przypadku widoczność obj będzie spójna w wielu wątkach (Załóżmy, że obj ma również wszystkie końcowe pola), ponieważ jest bezpiecznie skonstruowana przy użyciu ostatecznego słowa kluczowego.
W Scali nie wydaje się, że val kompiluje się do ostatecznego odniesienia, ale raczej val jest semantyką w Scali, która uniemożliwia ponowne przypisanie zmienna (zmienne końcowe Scala w konstruktorze ). Jeśli zmienne konstruktora scala nie są definiowane jako ostateczne, czy będą one cierpieć z tego samego problemu (podczas używania tych obiektów w aktorach)?
2 answers
Odpowiedź na inne pytanie jest myląca. Istnieją dwa znaczenia terminu final
: a) dla pól/metod Scala i metod Javy oznacza to "nie można nadpisać w podklasie" oraz b) Dla pól Javy i w JVM bytecode oznacza "pole musi być zainicjalizowane w konstruktorze i nie może być ponownie przypisane".
Parametry klasy oznaczone val
(lub, równoważnie, parametry klasy case bez modyfikatora) są rzeczywiście ostateczne w drugim sensie, a zatem bezpieczne dla wątku.
Oto dowód:
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
Lub z javap
, które można wygodnie uruchomić z 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);
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-10-02 18:21:03
Chyba źle zrozumiałem sposób kompilacji var. Stworzyłem przykładową klasę
class AVarTest(name:String) {
def printName() {
println(name)
}
}
Uciekłem javap -private
i to spowodowało
public class AVarTest extends java.lang.Object implements scala.ScalaObject{
private final java.lang.String name;
public void printName();
public AVarTest(java.lang.String);
}
I nazwa jest faktycznie skompilowana do finału.
Jest to również pokazane w Scala val musi być strzeżona z synchronizacją dla współbieżnego dostępu?
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:25:31