2012-09-06 12 views
40

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

  1. किसी भी setters
  2. मार्क के रूप में निजी
  3. सभी क्षेत्रों वर्ग अंतिम बनाओ प्रदान न करें

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

+0

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

+0

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

+1

सबक्लास को विधियों को ओवरराइड करने की अनुमति न दें - ऐसा करने का सबसे आसान तरीका कक्षा को अंतिम घोषित करना है। एक और परिष्कृत दृष्टिकोण कन्स्ट्रक्टर को निजी बनाने और कारखाने के तरीकों में उदाहरण बनाने के लिए है - https://docs.oracle.com/javase/tutorial/essential/concurrency/imstrat.html –

उत्तर

75

यदि आप 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 के व्यवहार अधिरोहित किया है एक नया, परिवर्तनशील पढ़ने के लिए क्षेत्र मेरे उपclass में घोषित किया। नतीजतन, आपकी कक्षा, जो शुरू में अपरिवर्तनीय दिखती है, वास्तव में अपरिवर्तनीय नहीं है। मैं Mutable ऑब्जेक्ट को पास कर सकता हूं जहां कहीं भी Immutable ऑब्जेक्ट की अपेक्षा की जाती है, जो ऑब्जेक्ट को वास्तव में अपरिवर्तनीय मानते हुए कोड के लिए बहुत बुरी चीजें कर सकती है। बेस क्लास को चिह्नित करना final इसे होने से रोकता है।

आशा है कि इससे मदद मिलती है!

+4

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

+8

@ आनंद- कल्पना कीजिए कि आपके पास एक ऐसा कार्य है जो 'अपरिवर्तनीय' तर्क लेता है। मैं उस समारोह में 'म्यूटेबल' ऑब्जेक्ट पास कर सकता हूं, क्योंकि 'उत्परिवर्तनीय अपरिवर्तनीय' बढ़ाता है। उस फ़ंक्शन के अंदर, जबकि आपको लगता है कि आपकी ऑब्जेक्ट अपरिवर्तनीय है, तो मेरे पास एक द्वितीयक थ्रेड हो सकता है जो फ़ंक्शन चलाता है और मान को बदलता है। मैं आपको एक 'म्यूटेबल' ऑब्जेक्ट भी दे सकता हूं जो फ़ंक्शन स्टोर करता है, फिर बाद में अपना मान बाहरी रूप से बदल देता है। दूसरे शब्दों में, यदि आपका फ़ंक्शन मानता है कि मान अपरिवर्तनीय है, तो यह आसानी से टूट सकता है, क्योंकि मैं आपको एक म्यूटेबल ऑब्जेक्ट दे सकता हूं और इसे बाद में बदल सकता हूं। क्या इसका कोई मतलब है? – templatetypedef

+0

@ templatetypedef- यह बेवकूफ लग सकता है, लेकिन वास्तव में मैं अभी भी स्पष्ट नहीं हूं ..लेट्स एक उदाहरण लेते हैं कि मेरे पास विधि शून्य मजाक है (अपरिवर्तनीय i) .. मैं इस विधि को पास करता हूं म्यूटेबल ऑब्जेक्ट कहता है .. अब मैं कैसे बदल सकता हूं ऑब्जेक्ट..क्या आप इसे कोड उदाहरण के संदर्भ में समझा सकते हैं या यदि आप कुछ और उदाहरण दे सकते हैं, तो मैं इसके साथ भी ठीक हूं .. – Anand

4

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

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

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

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

+2

यह सच है, लेकिन यह यहां क्यों जरूरी है? – templatetypedef

+1

हाँ सही, इसकी आवश्यकता क्यों है? – Anand

+0

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

5

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

+0

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

1

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

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

+0

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

+0

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

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 होने की गारंटी है। यह हैशिंग, समानता, समरूपता इत्यादि जैसी चीजों के साथ समस्याएं पैदा कर सकता है।

19

कई लोगों का मानना ​​है कि एक अपरिवर्तनीय वर्ग final आवश्यक नहीं है।

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

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

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

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

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

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

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

+1

यह ध्यान देने योग्य है कि जावा "अपेक्षा करता है", लेकिन यह लागू नहीं करता है, कि दो ऑब्जेक्ट्स 'एक्स' और' वाई 'दिया गया है,' एक्स.क्वल्स (वाई) 'का मान अपरिवर्तनीय होगा (जब तक 'एक्स' और' वाई 'एक ही ऑब्जेक्ट को संदर्भित करना जारी रखता है)। इसमें हैश कोड के बारे में समान उम्मीदें हैं। यह स्पष्ट है कि किसी को भी कंपाइलर को समकक्ष संबंधों और हैश कोड की अपरिवर्तनीयता को लागू करने की अपेक्षा नहीं करनी चाहिए (क्योंकि यह केवल सादा नहीं हो सकता है)। मुझे कोई कारण नहीं दिखता कि लोगों को किसी प्रकार के अन्य पहलुओं के लिए इसे लागू करने की उम्मीद करनी चाहिए। – supercat

+1

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

+1

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

9

संपूर्ण कक्षा अंतिम को चिह्नित न करें।

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

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

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

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

+0

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

+0

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

1

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

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

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

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

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

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

अधिक जानकारी के लिए नीचे दी गई यूआरएल

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

0

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

इसके अलावा, डिजाइन हमेशा लागत पर आता है। Every design that deserves the name means you have a conflict of goals

इसी के साथ

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

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

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

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

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

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

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