`प्राइवेट वैल` और` प्राइवेट फाइनल वैल` अलग क्यों हैं?


100

जब तक मैं स्कैला संदर्भ में धारा 4.1 नहीं देख लेता, तब तक मैं यही सोचता था private valऔर private final valएक ही जैसे थे:

एक स्थिर मान परिभाषा प्रपत्र का है

final val x = e

जहाँ e एक स्थिर अभिव्यक्ति है (.26.24)। अंतिम संशोधक मौजूद होना चाहिए और किसी प्रकार का एनोटेशन नहीं दिया जा सकता है। निरंतर मान x का संदर्भ स्वयं को निरंतर अभिव्यक्तियों के रूप में माना जाता है; उत्पन्न कोड में वे परिभाषा के दाईं ओर ई द्वारा प्रतिस्थापित किए जाते हैं।

और मैंने एक परीक्षा लिखी है:

class PrivateVal {
  private val privateVal = 0
  def testPrivateVal = privateVal
  private final val privateFinalVal = 1
  def testPrivateFinalVal = privateFinalVal
}

javap -c उत्पादन:

Compiled from "PrivateVal.scala"
public class PrivateVal {
  public int testPrivateVal();
    Code:
       0: aload_0       
       1: invokespecial #19                 // Method privateVal:()I
       4: ireturn       

  public int testPrivateFinalVal();
    Code:
       0: iconst_1      
       1: ireturn       

  public PrivateVal();
    Code:
       0: aload_0       
       1: invokespecial #24                 // Method java/lang/Object."<init>":()V
       4: aload_0       
       5: iconst_0      
       6: putfield      #14                 // Field privateVal:I
       9: return
}

बाइट कोड वैसा ही है जैसा कि स्काला संदर्भ ने कहा: private valनहीं है private final val

स्केलक बस के private valरूप में इलाज क्यों नहीं करता है private final val? क्या कोई अंतर्निहित कारण है?


28
दूसरे शब्दों में: चूंकि a valपहले से ही अपरिवर्तनीय है, इसलिए हमें finalScala में कीवर्ड की आवश्यकता क्यों है ? कंपाइलर सभी vals के समान व्यवहार क्यों नहीं कर सकता है final val?
जेस्पर

ध्यान दें कि privateस्कोप संशोधक package privateमें जावा के समान शब्दार्थ है । आपके कहने का मतलब हो सकता है private[this]
कॉनर डॉयल

5
@ConnorDoyle: पैकेज के रूप में निजी? मुझे ऐसा नहीं लगता है: privateइसका मतलब है कि यह केवल इस वर्ग के उदाहरणों के लिए दिखाई देता है, private[this]केवल इस उदाहरण - एक ही वर्ग के उदाहरणों को छोड़कर , privateकिसी को भी (एक ही पैकेज से शामिल) मूल्य का उपयोग करने की अनुमति नहीं देता है।
2142 पर Make42

जवाबों:


81

तो, यह सिर्फ एक अनुमान है, लेकिन यह जावा में एक बारहमासी झुंझलाहट थी जो दाएं हाथ की ओर एक शाब्दिक स्थैतिक चर के साथ निरंतरता के रूप में बायटेकोड में अंतर्भूत हो जाती है। यह सुनिश्चित करता है कि एक प्रदर्शन लाभ सुनिश्चित करता है, लेकिन यह परिभाषा की द्विआधारी संगतता का कारण बनता है अगर "स्थिर" कभी भी बदल जाए। अंतिम स्थिर वैरिएबल को परिभाषित करते समय जिसका मान बदलने की आवश्यकता हो सकती है, जावा प्रोग्रामर को विधि या कंस्ट्रक्टर के साथ मूल्य को इनिशियलाइज़ करने जैसे हैक्स का सहारा लेना पड़ता है।

स्कैला की एक घाटी जावा अर्थ में पहले से ही अंतिम है। ऐसा लगता है कि स्काला के डिजाइनर निरर्थक संशोधक फाइनल का उपयोग कर रहे हैं, जिसका अर्थ है "निरंतर मूल्य को अनुमति देना"। इसलिए स्काला प्रोग्रामर्स का हैक के लिए सहारा के बिना इस व्यवहार पर पूरा नियंत्रण है: यदि वे एक इनबिल्ट कंटीन्यू चाहते हैं, तो ऐसा मान जो कभी नहीं बदलना चाहिए, लेकिन तेज है, वे "फाइनल वैल" लिखते हैं। यदि वे बाइनरी संगतता को तोड़ने के बिना मूल्य बदलना चाहते हैं, तो बस "वैल"।


9
हां, यह गैर-निजी वैलेन्स का कारण है, लेकिन निजी वैल्स स्पष्ट रूप से अन्य वर्गों में इनबिल्ट नहीं हो सकते हैं और संगतता को उसी तरह से तोड़ सकते हैं।
एलेक्सी रोमानोव

3
जब मैं बदलता हूं तो क्या कोई बाइनरी संगतता समस्या private valहै private final val?
यांग बो

1
@ स्टीववे-वाल्डमैन क्षमा करें, क्या आपको valअपने दूसरे पैराग्राफ में मतलब है?
यांग बो

1
बाइनरी संगतता के बारे में जावा में अंतिम स्थिर चर पर विवरण यहां दिए गए हैं - docs.oracle.com/javase/specs/jls/se7/html/…
Eran Medan

8

मुझे लगता है कि यहाँ भ्रम की स्थिति अंतिम शब्दार्थ के साथ अपरिवर्तनीयता से उत्पन्न होती है। vals को बाल वर्गों में ओवरराइड किया जा सकता है और इसलिए जब तक कि स्पष्ट रूप से चिह्नित नहीं किया जाता है तब तक इसे अंतिम नहीं माना जा सकता है।

@ ब्रायन REPL लाइन स्तर पर वर्ग गुंजाइश प्रदान करता है। देख:

scala> $iw.getClass.getPackage
res0: Package = package $line3

scala> private val x = 5
<console>:5: error: value x cannot be accessed in object $iw
  lazy val $result = `x`

scala> private val x = 5; println(x);
5

1
मैं बात कर रहा हूँ private val। क्या इसे खत्म किया जा सकता है?
यांग बो

नहीं, निजी वेल को ओवरराइड नहीं किया जा सकता है। आप एक उपवर्ग में एक ही नाम के साथ एक और निजी घाटी को फिर से परिभाषित कर सकते हैं, लेकिन यह पूरी तरह से अलग घाटी है जो बस एक ही नाम के लिए होती है। (पुराने के सभी संदर्भ अभी भी पुराने को संदर्भित करेंगे।)
ऐज

1
यह सिर्फ इस अतिरंजित व्यवहार प्रतीत नहीं होता है, क्योंकि मैं दुभाषिया पर एक अंतिम वैल (या यहां तक ​​कि एक अंतिम संस्करण) बना सकता हूं, बिना किसी वर्ग के संदर्भ में।
nairbv
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.