2011-10-02 9 views
25

जावा में, एकाधिक थ्रेड (और सामान्य रूप से) में ऑब्जेक्ट का उपयोग करते समय, फ़ील्ड को अंतिम बनाने के लिए अच्छा अभ्यास है। उदाहरण के लिए,समसामयिक दृश्यता के लिए स्कैला फाइनल बनाम वैल

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

इस मामले में, obj की दृश्यता लगातार भर में एक से अधिक थ्रेड के बाद से इसे सुरक्षित रूप से अंतिम कीवर्ड का उपयोग कर निर्माण किया है (मान लेते हैं obj सभी अंतिम क्षेत्रों के साथ-साथ है चलो) हो जाएगा।

स्कैला में, यह वैल संकलन को अंतिम संदर्भ में नहीं दिखाता है, बल्कि वैल स्कैला में अर्थशास्त्र है जो आपको एक चर (Scala final variables in constructor) को पुन: असाइन करने से रोकता है। यदि स्कैला कन्स्ट्रक्टर वैरिएबल को अंतिम के रूप में परिभाषित नहीं किया गया है, तो क्या वे एक ही समस्या से पीड़ित होंगे (जब अभिनेताओं में इन वस्तुओं का उपयोग करते हैं)?

उत्तर

44

में दिखाया गया है अन्य सवाल का जवाब भ्रामक है। final शब्द के दो अर्थ हैं: ए) स्कैला फ़ील्ड/विधियों और जावा विधियों के लिए इसका अर्थ है "जावाक्लियंस में ओवरराइड नहीं किया जा सकता" और बी) जावा फ़ील्ड के लिए और जेवीएम बाइटकोड में इसका मतलब है "क्षेत्र को कन्स्ट्रक्टर में प्रारंभ किया जाना चाहिए और फिर से असाइन नहीं किया जा सकता "।

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, जो आसानी से आरईपीएल से चलाया जा सकता के साथ:

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); 
} 
+0

उस स्पष्टीकरण के लिए धन्यवाद। क्या आप उस प्रश्न पर अपना अपडेट देख सकते हैं? मैं बिना किसी संशोधक वाले गैर-केस क्लास के लिए अंतिम रूप में घोषित कन्स्ट्रक्टर वेरिएबल्स (जैसा कि जावा में दिखाया गया है) को भी देख रहा हूं। –

+0

@ संक्षिप्त नाम, मैं आपके प्रश्न का उत्तर खोजने की कोशिश कर रहा हूं, [स्कैला में अपरिवर्तनीयता और थ्रेड-सुरक्षा] (http://stackoverflow.com/questions/32113124/immutability-and-thread-safety-in- स्केला)। जैसा कि आप जानते हैं, जावा में 'अंतिम' कीवर्ड का उपयोग सीटीआर के निर्देशों के स्थानांतरण से बचने के लिए भी किया जाता है, जैसा कि [इस] में बताया गया है (https://www.cs.umd.edu/~pugh/java/memoryModel /jsr-133-faq.html#finalRight) लिंक। इसलिए, यदि मैंने सही जवाब समझा है, तो स्काला कक्षा में 'वैल' फ़ील्ड का उपयोग करके जावा क्लास में' अंतिम 'फ़ील्ड घोषित करने के बराबर है, जिससे जेएमएम ठीक तरह से काम कर रहा है? –

1

मुझे लगता है कि मुझे गलत समझा जा सकता है कि कैसे विविध संकलित किया गया है। मैं नमूना वर्ग

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

मैं javap -private भाग गया बनाया है और वह

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

में हुई और नाम वास्तव में अंतिम करने के लिए संकलित किया गया है।

यह भी Scala val has to be guarded with synchronized for concurrent access?

+2

ध्यान दें कि 2.9.0.1 (शायद पहले) एकमात्र कारण है कि आप अंत के रूप में फ़ील्ड नाम के साथ है क्योंकि आपने इसे प्रिंटनाम में संदर्भित किया है। यदि कोई विधि एक ctor तर्क का संदर्भ नहीं देती है तो यह कोई फ़ील्ड उत्पन्न नहीं करता है। –

संबंधित मुद्दे