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)?
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é".
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);
}
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é?