कोई जावा में अपरिवर्तनीय वर्ग के फाइनल की घोषणा क्यों करेगा?


83

मैंने पढ़ा कि जावा में एक कक्षा को अपरिवर्तनीय बनाने के लिए , हमें निम्नलिखित कार्य करना चाहिए,

  1. कोई बसाहट प्रदान न करें
  2. सभी फ़ील्ड को निजी के रूप में चिह्नित करें
  3. कक्षा को अंतिम रूप दें

चरण 3 की आवश्यकता क्यों है? मुझे कक्षा को क्यों चिह्नित करना चाहिए final?


java.math.BigIntegerवर्ग उदाहरण है, यह मान अपरिवर्तनीय है लेकिन यह अंतिम नहीं है।
नंदकुमार टेकले

@ नंदकुमार यदि आपके पास कोई है BigInteger, तो आप नहीं जानते कि यह अपरिवर्तनीय है या नहीं। यह एक गड़बड़ डिजाइन है। / java.io.Fileएक अधिक दिलचस्प उदाहरण है।
टॉम हॉकिन -

1
उपवर्गों को विधियों को ओवरराइड करने की अनुमति न दें - ऐसा करने का सबसे सरल तरीका वर्ग को अंतिम घोषित करना है। एक और अधिक परिष्कृत तरीका है, निर्माता को निजी बनाने के लिए और कारखाने के तरीकों में निर्माण उदाहरणों से - docs.oracle.com/javase/tutorial/essential/concurrency/…
Raúl

1
@mkobit Fileदिलचस्प है क्योंकि यह भरोसेमंद होने की संभावना है, और इसलिए TOCTOU (समय / उपयोग का समय) हमलों का नेतृत्व करता है। विश्वसनीय कोड यह जांचता है कि Fileएक स्वीकार्य मार्ग है और फिर पथ का उपयोग करता है। एक उपवर्ग Fileचेक और उपयोग के बीच मूल्य बदल सकता है।
टॉम हॉल्टिन - 17:14

1
Make the class finalया सुनिश्चित करें कि सभी उपवर्ग अपरिवर्तनीय हैं
O.Badr

जवाबों:


138

यदि आप कक्षा को चिन्हित नहीं करते हैं final, तो मेरे लिए यह संभव हो सकता है कि मैं आपके प्रतीत होने वाले अपरिवर्तनीय वर्ग को वास्तव में परिवर्तनशील बना सकूं। उदाहरण के लिए, इस कोड पर विचार करें:

public class Immutable {
     private final int value;

     public Immutable(int value) {
         this.value = value;
     }

     public int getValue() {
         return value;
     }
}

अब, मान लीजिए कि मैं निम्नलिखित कार्य करता हूं:

public class Mutable extends Immutable {
     private int realValue;

     public Mutable(int value) {
         super(value);

         realValue = value;
     }

     public int getValue() {
         return realValue;
     }
     public void setValue(int newValue) {
         realValue = newValue;
     }

    public static void main(String[] arg){
        Mutable obj = new Mutable(4);
        Immutable immObj = (Immutable)obj;              
        System.out.println(immObj.getValue());
        obj.setValue(8);
        System.out.println(immObj.getValue());
    }
}

ध्यान दें कि मेरे Mutableउपवर्ग में, मैंने getValueअपने उपवर्ग में घोषित एक नए, परिवर्तनशील क्षेत्र को पढ़ने के व्यवहार को ओवरराइड किया है । परिणामस्वरूप, आपकी कक्षा, जो शुरू में अपरिवर्तनीय लगती है, वास्तव में अपरिवर्तनीय नहीं है। Mutableजहाँ भी किसी Immutableवस्तु की अपेक्षा की जाती है, मैं इस वस्तु को पास कर सकता हूँ, जो कि वस्तु को वास्तव में अपरिवर्तनीय मानने के लिए वेरी बैड थिंग्स को कर सकता है। बेस क्लास finalको चिह्नित करना ऐसा होने से रोकता है।

उम्मीद है की यह मदद करेगा!


13
अगर मैं Mutable m = new Mutable (4) करता हूं; m.setValue (5); यहाँ, मैं Mutable क्लास ऑब्जेक्ट के साथ खेल रहा हूँ, Immutable क्लास ऑब्जेक्ट नहीं। इसलिए, मैं अभी भी उलझन में हूँ कि Immutable क्लास अपरिवर्तनीय क्यों नहीं है
आनंद

18
@ आनंद- कल्पना कीजिए कि आपके पास एक फ़ंक्शन है जो Immutableएक तर्क लेता है। मैं Mutableउस फ़ंक्शन के लिए ऑब्जेक्ट पास कर सकता हूं , क्योंकि Mutable extends Immutable। उस फ़ंक्शन के अंदर, जबकि आपको लगता है कि आपकी वस्तु अपरिवर्तनीय है, मेरे पास एक माध्यमिक धागा हो सकता है जो फ़ंक्शन चलता है और मूल्य बदलता है। मैं आपको एक Mutableऑब्जेक्ट भी दे सकता हूं जो फ़ंक्शन स्टोर करता है, फिर बाद में इसका मूल्य बाहरी रूप से बदल सकता है। दूसरे शब्दों में, यदि आपका फ़ंक्शन मान लेता है, तो अपरिवर्तनीय है, यह आसानी से टूट सकता है, क्योंकि मैं आपको एक परिवर्तनशील वस्तु दे सकता हूं और बाद में इसे बदल सकता हूं। क्या इसका कोई मतलब है?
templatetypedef

6
@ आनंद- जिस विधि से आप Mutableवस्तु को पास करते हैं वह वस्तु नहीं बदलेगी। चिंता का विषय यह है कि यह विधि मान सकती है कि वस्तु अपरिवर्तनीय है जब यह वास्तव में नहीं है। उदाहरण के लिए, विधि यह मान सकती है कि, क्योंकि यह सोचता है कि वस्तु अपरिवर्तनीय है, इसका उपयोग कुंजी में किया जा सकता है HashMap। मैं तब उस फ़ंक्शन Mutableको एक कुंजी के रूप में संग्रहीत करने के लिए प्रतीक्षा कर रहा था , एक वस्तु के रूप में संग्रहीत करने के लिए इसे पारित कर सकता है Mutable। अब, उस में लुकअप HashMapविफल हो जाएगा, क्योंकि मैंने ऑब्जेक्ट से जुड़ी कुंजी को बदल दिया है। क्या इसका कोई मतलब है?
templatetypedef

3
@ templatetypedef- हां, मुझे अब मिल गया है..बस कहते हैं कि एक भयानक विवरण था..इतना समझ लेने के लिए थोड़ा समय लिया
आनंद 19

1
@ सैम- यह सही है। हालाँकि, यह वास्तव में मायने नहीं रखता, क्योंकि ओवरराइड फ़ंक्शंस उस चर को फिर से संदर्भित नहीं करते हैं।
templatetypedef

47

बहुत से लोग मानते हैं कि, अपरिवर्तनीय वर्ग बनाने के विपरीत finalहै नहीं की आवश्यकता है।

अपरिवर्तनीय कक्षाएं बनाने के लिए मानक तर्क finalयह है कि यदि आप ऐसा नहीं करते हैं, तो उपवर्ग उत्परिवर्तन जोड़ सकते हैं, जिससे सुपरक्लास के अनुबंध का उल्लंघन हो सकता है। वर्ग के ग्राहक अपरिवर्तनीयता मानेंगे, लेकिन जब उनके नीचे से कुछ उत्परिवर्तित होगा तो आश्चर्य होगा।

यदि आप इस तर्क को उसके तार्किक चरम पर ले जाते हैं, तो सभी विधियाँ बनाई जानी चाहिए final, क्योंकि अन्यथा एक उपवर्ग इस तरह से एक विधि को ओवरराइड कर सकता है जो उसके सुपरक्लास के अनुबंध के अनुरूप नहीं है। यह दिलचस्प है कि अधिकांश जावा प्रोग्रामर इसे हास्यास्पद के रूप में देखते हैं, लेकिन किसी तरह इस विचार के साथ ठीक हैं कि अपरिवर्तनीय कक्षाएं होनी चाहिए final। मुझे संदेह है कि इसका जावा प्रोग्रामर के साथ कुछ ऐसा है जो सामान्य रूप से अपरिवर्तनीयता की धारणा के साथ पूरी तरह से सहज नहीं है, और शायद finalजावा में कीवर्ड के कई अर्थों से संबंधित कुछ अजीब तरह की सोच है ।

अपने सुपरक्लास के अनुबंध के अनुरूप कुछ ऐसा नहीं है जिसे कंपाइलर द्वारा हमेशा लागू किया जा सकता है या होना चाहिए। कंपाइलर आपके अनुबंध के कुछ पहलुओं को लागू कर सकता है (जैसे: तरीकों का एक न्यूनतम सेट और उनके प्रकार के हस्ताक्षर) लेकिन विशिष्ट अनुबंध के कई हिस्से हैं जो कंपाइलर द्वारा लागू नहीं किए जा सकते हैं।

अपरिवर्तनीयता एक वर्ग के अनुबंध का हिस्सा है। यह उन कुछ चीज़ों से थोड़ा अलग है, जिनका लोग अधिक उपयोग करते हैं, क्योंकि यह कहता है कि वर्ग (और सभी उपवर्ग) क्या नहीं कर सकते , जबकि मुझे लगता है कि अधिकांश जावा (और आमतौर पर ओओपी) प्रोग्रामर अनुबंधों के बारे में सोचते हैं। एक वर्ग क्या कर सकता है, वह नहीं जो वह नहीं कर सकता।

अपरिहार्यता भी केवल एक ही विधि से अधिक प्रभावित होती है - यह पूरे उदाहरण को प्रभावित करती है - लेकिन यह वास्तव में जावा के काम करने के तरीके equalsऔर तरीकों से बहुत अलग नहीं है hashCode। उन दो विधियों में एक विशिष्ट अनुबंध होता है Object। यह अनुबंध बहुत सावधानी से उन चीजों को देता है जो ये विधियां नहीं कर सकती हैं। इस अनुबंध को उपवर्गों में अधिक विशिष्ट बनाया गया है। ओवरराइड करना equalsया hashCodeअनुबंध का उल्लंघन करने वाले तरीके से करना बहुत आसान है । वास्तव में, यदि आप इन दो तरीकों में से केवल एक को दूसरे के बिना ओवरराइड करते हैं, तो संभावना है कि आप अनुबंध का उल्लंघन कर रहे हैं। तो चाहिए equalsऔर hashCodeघोषित किया गया है finalमें Objectइस से बचने के लिए? मुझे लगता है कि अधिकांश यह तर्क देंगे कि उन्हें नहीं करना चाहिए। इसी तरह, अपरिवर्तनीय कक्षाएं बनाना आवश्यक नहीं हैfinal

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

तो आपके चरण 3 का एक सही संस्करण होगा: "वर्ग को अंतिम बनाएं या, जब उपवर्ग के लिए डिज़ाइन किया जाए, तो स्पष्ट रूप से दस्तावेज़ दें कि सभी उपवर्गों को अपरिवर्तनीय होना चाहिए।"


3
यह ध्यान देने योग्य है कि जावा "उम्मीद" करता है, लेकिन लागू नहीं करता है, जो दो वस्तुओं को दिया गया है Xऔर Y, का मूल्य X.equals(Y)अपरिवर्तनीय होगा (जब तक Xऔर Yसमान वस्तुओं को संदर्भित करना जारी रखें)। हैश कोड के बारे में भी ऐसी ही उम्मीदें हैं। यह स्पष्ट है कि किसी को भी समकक्ष संबंधों और हैश कोड की अपरिहार्यता को लागू करने की उम्मीद नहीं करनी चाहिए (क्योंकि यह सिर्फ सादा नहीं हो सकता है)। मुझे लगता है कि लोग बिना किसी प्रकार के अन्य पहलुओं के लिए इसे लागू करने की अपेक्षा करते हैं।
सुपरकैट

1
इसके अलावा, ऐसे कई मामले हैं जहां एक अमूर्त प्रकार होना उपयोगी हो सकता है जिसका अनुबंध अपरिवर्तनीयता को निर्दिष्ट करता है। उदाहरण के लिए, किसी के पास एक अमूर्त ImmutableMatrix प्रकार हो सकता है, जो एक समन्वय जोड़ी दिया जाता है, एक रिटर्न देता है double। कोई एक ऐसा सामान प्राप्त कर सकता है GeneralImmutableMatrixजो एक बैकिंग स्टोर के रूप में एक सरणी का उपयोग करता है, लेकिन एक यह भी हो सकता है कि उदाहरण के लिए, ImmutableDiagonalMatrixजो विकर्ण के साथ वस्तुओं की एक सरणी को स्टोर करता है (आइटम X को पढ़ना, Y उपज होगा Arr [X] यदि X == y और शून्य अन्यथा) ।
सुपरकट

2
मुझे यह स्पष्टीकरण सबसे अच्छा लगता है। हमेशा एक अपरिवर्तनीय वर्ग बनाने से finalइसकी उपयोगिता सीमित हो जाती है, खासकर जब आप एक एपीआई डिज़ाइन कर रहे हैं, जिसका अर्थ है विस्तारित होना। थ्रेड-सेफ्टी के हित में, यह आपकी कक्षा को जितना संभव हो सके अपरिवर्तनीय बनाने के लिए समझ में आता है, लेकिन इसे एक्स्टेंसिबल रखें। आप protected finalइसकी जगह खेत बना सकते हैं private final। फिर, स्पष्ट रूप से अपरिवर्तनीयता और थ्रेड-सुरक्षा गारंटी का पालन करने वाले उप-वर्गों के बारे में एक अनुबंध (प्रलेखन में) स्थापित करें।
29:29 पर curioustechizen

4
+1 - बलोच बोली तक मैं आपके साथ हूं। हमें इतना पागल होने की जरूरत नहीं है। 99% कोडिंग सहकारी हैं। कोई बड़ी बात नहीं है अगर किसी को वास्तव में किसी चीज को ओवरराइड करने की आवश्यकता है, तो उन्हें जाने दें। हममें से 99% लोग कुछ कोर API जैसे String या Collection नहीं लिख रहे हैं। बलोच की बहुत सारी सलाह, दुर्भाग्य से, इस तरह के उपयोग के मामलों पर आधारित हैं। वे वास्तव में अधिकांश प्रोग्रामर, विशेष रूप से नए लोगों के लिए सहायक नहीं हैं।
झोंगयू

मैं अपरिवर्तनीय वर्ग बनाना पसंद करूंगा final। सिर्फ इसलिए equalsऔर hashcodeअंतिम नहीं हो सकता इसका मतलब यह नहीं है कि मैं इसे अपरिवर्तनीय वर्ग के लिए सहन कर सकता हूं, जब तक कि मेरे पास ऐसा करने का कोई वैध कारण नहीं है, और इस मामले में मैं एक रक्षा पंक्ति के रूप में प्रलेखन या परीक्षण का उपयोग कर सकता हूं।
ओ। बद्र

21

पूरे वर्ग के फाइनल को चिह्नित न करें।

एक अपरिवर्तनीय वर्ग को विस्तारित करने की अनुमति देने के लिए वैध कारण हैं, जैसा कि कुछ अन्य उत्तरों में बताया गया है, इसलिए वर्ग को अंतिम रूप से चिह्नित करना हमेशा एक अच्छा विचार नहीं है।

अपने गुणों को निजी और अंतिम रूप से चिह्नित करना बेहतर है और यदि आप "अनुबंध" की रक्षा करना चाहते हैं, तो अपने गेटर्स को अंतिम रूप दें।

इस तरह से आप वर्ग को विस्तारित करने की अनुमति दे सकते हैं (हाँ संभवतः एक उत्परिवर्तित वर्ग द्वारा भी) हालाँकि आपकी कक्षा के अपरिवर्तनीय पहलुओं की रक्षा की जाती है। गुण निजी हैं और उन तक पहुँचा नहीं जा सकता है, इन संपत्तियों के लिए गेट अंतिम हैं और उन्हें ओवरराइड नहीं किया जा सकता है।

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


1
मैं बल्कि एक अलग वर्ग में सभी अपरिवर्तनीय पहलुओं को समाहित करता हूं और इसका उपयोग रचना के माध्यम से करता हूं। कोड की एक इकाई में उत्परिवर्तनीय और अपरिवर्तनीय अवस्था के मिश्रण की तुलना में यह करना आसान होगा।
toniedzwiedz

1
पूर्णतया सहमत। रचना इसे पूरा करने का एक बहुत अच्छा तरीका होगा, बशर्ते आपके परस्पर वर्ग में आपका अपरिवर्तनीय वर्ग हो। यदि आपकी संरचना इसके आसपास का दूसरा तरीका है तो यह एक अच्छा आंशिक समाधान होगा।
जस्टिन ओह्म्स

5

यदि यह अंतिम नहीं है, तो कोई भी वर्ग का विस्तार कर सकता है और जो कुछ भी उन्हें पसंद है, जैसे कि बसने वाले प्रदान करना, अपने निजी चर को छाया देना और मूल रूप से इसे परिवर्तनशील बनाना है।


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

4

वह आपकी कक्षा का विस्तार करने वाली अन्य कक्षाओं को बाधित करता है।

अंतिम वर्ग को अन्य वर्गों द्वारा विस्तारित नहीं किया जा सकता है।

यदि कोई वर्ग उस वर्ग का विस्तार करता है जिसे आप अपरिवर्तनीय बनाना चाहते हैं, तो यह विरासत के सिद्धांतों के कारण कक्षा की स्थिति को बदल सकता है।

बस स्पष्ट करें "यह बदल सकता है"। सबक्लास सुपरक्लास व्यवहार को ओवरराइड करने की विधि (जैसे टेम्प्लेटेटिपेड / टेड हॉप उत्तर की तरह) का उपयोग कर सकता है


2
यह सच है, लेकिन यहाँ क्यों आवश्यक है?
templatetypedef

@templatetypedef: आप बहुत तेज़ हैं। मैं अपना उत्तर सहायक बिंदुओं के साथ संपादित कर रहा हूं।
कोसा

4
अभी आपका उत्तर इतना अस्पष्ट है कि मुझे नहीं लगता कि यह प्रश्न का उत्तर देता है। आपको "इनहेरिटेंस सिद्धांतों के कारण वर्ग की स्थिति बदल सकती है" से क्या मतलब है? जब तक आप पहले से ही नहीं जानते कि आपको इसे क्यों चिह्नित करना चाहिए final, मैं नहीं देख सकता कि यह उत्तर कैसे मदद करता है।
templatetypedef

4

यदि आप इसे अंतिम नहीं बनाते हैं तो मैं इसे विस्तारित कर सकता हूं और इसे गैर-परिवर्तनशील बना सकता हूं।

public class Immutable {
  privat final int val;
  public Immutable(int val) {
    this.val = val;
  }

  public int getVal() {
    return val;
  }
}

public class FakeImmutable extends Immutable {
  privat int val2;
  public FakeImmutable(int val) {
    super(val);
  }

  public int getVal() {
    return val2;
  }

  public void setVal(int val2) {
    this.val2 = val2;
  }
}

अब, मैं FakeImmutable को किसी भी वर्ग से पारित कर सकता हूं जो अपरिवर्तनीय की अपेक्षा करता है, और यह अपेक्षित अनुबंध के रूप में व्यवहार नहीं करेगा।


2
मुझे लगता है कि यह मेरे उत्तर के समान है।
templatetypedef 19

हां, पोस्टिंग के माध्यम से आधे रास्ते की जाँच की, कोई नया जवाब नहीं दिया। और फिर जब पोस्ट किया, वहाँ तुम्हारा था, मुझसे 1 मिनट पहले। कम से कम हमने हर चीज के लिए समान नामों का उपयोग नहीं किया।
रोजर लिंडजो सेप

एक सुधार: FakeImmutable वर्ग में, कंस्ट्रक्टर का नाम FakeImmutable नहीं होना चाहिए अपरिहार्य
सनी गुप्ता

2

अपरिवर्तनीय वर्ग बनाने के लिए वर्ग को अंतिम रूप से चिह्नित करना अनिवार्य नहीं है।

मुझे ऐसे उदाहरणों में से एक जावा क्लासेस से ही लेना चाहिए "बिगइन्टेगर" वर्ग अपरिवर्तनीय है, लेकिन यह अंतिम नहीं है।

वास्तव में इम्युनिटी एक अवधारणा है जिसके अनुसार जिस वस्तु का निर्माण किया जाता है उसके बाद उसे संशोधित नहीं किया जा सकता है।

आइए, जेवीएम के नज़रिए से सोचें, जेवीएम के नज़रिए से सभी थ्रेड्स को ऑब्जेक्ट की एक ही कॉपी शेयर करनी चाहिए और किसी भी थ्रेड को एक्सेस करने से पहले इसे पूरी तरह से बनाया जाना चाहिए और इसके निर्माण के बाद ऑब्जेक्ट की स्थिति नहीं बदलती है।

अपरिवर्तनशीलता का अर्थ है कि किसी भी तरह से वस्तु के बनने के बाद यो की स्थिति में कोई बदलाव नहीं होता है और यह तीन अंगूठे नियमों द्वारा प्राप्त किया जाता है जो कंपाइलर को यह पहचानने के लिए बनाता है कि वर्ग अपरिवर्तनीय है और वे निम्नानुसार हैं: -

  • सभी गैर निजी क्षेत्र अंतिम होने चाहिए
  • सुनिश्चित करें कि कक्षा में कोई ऐसा तरीका नहीं है जो वस्तु के क्षेत्रों को प्रत्यक्ष या अप्रत्यक्ष रूप से बदल सके
  • कक्षा में परिभाषित किसी भी वस्तु संदर्भ को कक्षा से बाहर संशोधित नहीं किया जा सकता है

अधिक जानकारी के लिए नीचे दिए गए URL को देखें

http://javaunturnedtopics.blogspot.in/2016/07/can-we-create-immutable-class-without.html


1

मान लीजिए कि आपके पास निम्न वर्ग है:

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

public class PaymentImmutable {
    private final Long id;
    private final List<String> details;
    private final Date paymentDate;
    private final String notes;

    public PaymentImmutable (Long id, List<String> details, Date paymentDate, String notes) {
        this.id = id;
        this.notes = notes;
        this.paymentDate = paymentDate == null ? null : new Date(paymentDate.getTime());
        if (details != null) {
            this.details = new ArrayList<String>();

            for(String d : details) {
                this.details.add(d);
            }
        } else {
            this.details = null;
        }
    }

    public Long getId() {
        return this.id;
    }

    public List<String> getDetails() {
        if(this.details != null) {
            List<String> detailsForOutside = new ArrayList<String>();
            for(String d: this.details) {
                detailsForOutside.add(d);
            }
            return detailsForOutside;
        } else {
            return null;
        }
    }

}

फिर आप इसे विस्तारित करते हैं और इसकी अपरिवर्तनीयता को तोड़ते हैं।

public class PaymentChild extends PaymentImmutable {
    private List<String> temp;
    public PaymentChild(Long id, List<String> details, Date paymentDate, String notes) {
        super(id, details, paymentDate, notes);
        this.temp = details;
    }

    @Override
    public List<String> getDetails() {
        return temp;
    }
}

यहाँ हम इसका परीक्षण करते हैं:

public class Demo {

    public static void main(String[] args) {
        List<String> details = new ArrayList<>();
        details.add("a");
        details.add("b");
        PaymentImmutable immutableParent = new PaymentImmutable(1L, details, new Date(), "notes");
        PaymentImmutable notImmutableChild = new PaymentChild(1L, details, new Date(), "notes");

        details.add("some value");
        System.out.println(immutableParent.getDetails());
        System.out.println(notImmutableChild.getDetails());
    }
}

आउटपुट परिणाम होगा:

[a, b]
[a, b, some value]

जैसा कि आप देख सकते हैं कि मूल कक्षा अपनी अपरिवर्तनीयता को बनाए रखते हुए, बच्चे की कक्षा में परिवर्तनशील हो सकती है। नतीजतन, आपके डिजाइन में आप यह सुनिश्चित नहीं कर सकते कि आप जिस वस्तु का उपयोग कर रहे हैं वह अपरिवर्तनीय है, जब तक कि आप अपने वर्ग को अंतिम नहीं बनाते।


0

मान लीजिए कि निम्न वर्ग नहीं थे final:

public class Foo {
    private int mThing;
    public Foo(int thing) {
        mThing = thing;
    }
    public int doSomething() { /* doesn't change mThing */ }
}

यह स्पष्ट रूप से अपरिवर्तनीय है क्योंकि यहां तक ​​कि उपवर्ग भी संशोधित नहीं कर सकते हैं mThing। हालांकि, एक उपवर्ग परस्पर हो सकता है:

public class Bar extends Foo {
    private int mValue;
    public Bar(int thing, int value) {
        super(thing);
        mValue = value;
    }
    public int getValue() { return mValue; }
    public void setValue(int value) { mValue = value; }
}

अब एक ऐसी वस्तु जो किसी प्रकार के वेरिएबल के लिए असाइन की जाती है, को Fooअब mmutable होने की गारंटी नहीं है। यह हैशिंग, समानता, संगामिति, आदि जैसी चीजों के साथ समस्या पैदा कर सकता है।


0

अपने आप से डिजाइन का कोई मूल्य नहीं है। डिजाइन हमेशा एक लक्ष्य को प्राप्त करने के लिए उपयोग किया जाता है। यहाँ लक्ष्य क्या है? क्या हम कोड में आश्चर्य की मात्रा को कम करना चाहते हैं? क्या हम बग्स को रोकना चाहते हैं? क्या हम आँख बंद करके नियमों का पालन कर रहे हैं?

इसके अलावा, डिजाइन हमेशा एक लागत पर आता है। प्रत्येक डिजाइन जो नाम के योग्य है, इसका मतलब है कि आपके पास लक्ष्यों का संघर्ष है

इसे ध्यान में रखते हुए, आपको इन सवालों के जवाब खोजने की जरूरत है:

  1. कितने स्पष्ट कीड़े इसे रोकेंगे?
  2. कितने सूक्ष्म कीड़े इसे रोकेंगे?
  3. यह कितनी बार अन्य कोड को और अधिक जटिल बना देगा (= अधिक त्रुटि प्रवण)?
  4. क्या यह परीक्षण को आसान या कठिन बनाता है?
  5. आपके प्रोजेक्ट में डेवलपर्स कितने अच्छे हैं? स्लेज हथौड़ा के साथ उन्हें कितना मार्गदर्शन चाहिए?

कहते हैं कि आपकी टीम में कई जूनियर डेवलपर हैं। वे किसी भी बेवकूफी की कोशिश करेंगे क्योंकि वे अपनी समस्याओं के लिए अच्छे समाधान नहीं जानते हैं, फिर भी। वर्ग फाइनल बनाने से कीड़े (अच्छे) को रोका जा सकता है, लेकिन कोड में हर जगह इन सभी वर्गों को एक उत्परिवर्ती में कॉपी करने जैसे "चतुर" समाधान भी आ सकते हैं।

दूसरी ओर, finalहर जगह इस्तेमाल होने के बाद एक वर्ग बनाना बहुत कठिन होगा, लेकिन finalकक्षा को गैर- finalबाद में बनाना आसान है, अगर आपको पता चले कि आपको इसे विस्तारित करने की आवश्यकता है।

यदि आप ठीक से इंटरफेस का उपयोग करते हैं, तो आप हमेशा इंटरफ़ेस का उपयोग करके और फिर बाद में जरूरत पड़ने पर एक परिवर्तनशील कार्यान्वयन जोड़कर "मुझे इस परिवर्तनशील बनाने की आवश्यकता" से बच सकते हैं।

निष्कर्ष: इस उत्तर के लिए कोई "सर्वश्रेष्ठ" समाधान नहीं है। यह निर्भर करता है कि आप किस कीमत पर तैयार हैं और आपको किस कीमत का भुगतान करना है।


0

बराबरी का डिफ़ॉल्ट अर्थ () संदर्भात्मक समानता के समान है। अपरिवर्तनीय डेटा प्रकारों के लिए, यह लगभग हमेशा गलत होता है। तो आपको अपने स्वयं के कार्यान्वयन के साथ इसे बदलने के बराबर () विधि को ओवरराइड करना होगा। संपर्क

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.