Scala final vs val pour la visibilité simultanée

en Java, lorsqu'on utilise un objet à travers plusieurs threads (et en général), il est recommandé de rendre les champs définitifs. Par exemple,

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

dans ce cas, la visibilité d'obj sera cohérente à travers plusieurs threads (supposons que obj ait tous les champs finaux aussi) puisqu'il est construit en toute sécurité en utilisant le mot-clé final.

dans scala, il ne semble pas que val compile vers le bas à une référence finale, mais plutôt val est sémantique dans scala qui vous empêche de réassigner une variable ( Scala variables finales dans le constructeur ). Si les variables du constructeur de scala ne sont pas définies comme finales, souffriront-elles du même problème (lors de l'utilisation de ces objets dans actors)?

27
demandé sur Community 2011-10-02 17:29:36

2 réponses

La réponse à l'autre question est trompeuse. Il y a deux significations du terme final : a) pour les champs/méthodes Scala et les méthodes Java, cela signifie "ne peut pas être outrepassé dans une sous-classe" et b) pour les champs Java et dans le bytecode JVM, cela signifie "le champ doit être initialisé dans le constructeur et ne peut pas être réassigné".

Les paramètres de classe

marqués avec val (ou, de manière équivalente, les paramètres de classe de cas sans modificateur) sont en effet définitifs au second sens, et donc thread-safe.

voici la preuve:

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

ou avec javap , qui peut être commodément exécuté à partir de la RÉPL:

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);
}
47
répondu retronym 2011-10-02 18:21:03

je pense que j'ai peut-être mal compris comment var est compilé. J'ai créé la classe échantillon

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

j'ai couru javap -private et il en est résulté une 151940920"

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

et le nom est en fait compilé en final.

Ceci est aussi montré dans Scala val doit être gardé avec synchronisé pour accès simultané?

1
répondu Jeff Storey 2017-05-23 12:25:31