जावा में अपरिवर्तनीय वस्तुओं का निर्माण कैसे करें?


83

जावा में अपरिवर्तनीय वस्तुओं का निर्माण कैसे करें?

किन वस्तुओं को अपरिवर्तनीय कहा जाना चाहिए?

अगर मेरे पास सभी स्थिर सदस्यों के साथ वर्ग है तो क्या यह अपरिवर्तनीय है?



1
ऊपर जुड़ा हुआ प्रश्न समान नहीं है, लेकिन उस प्रश्न के उत्तर को आपके सभी खोज का जवाब देना चाहिए।
जोकिम सॉर

यदि आपकी कक्षा सभी स्थिर सदस्य हैं, तो यह स्टेटलेस है (कोई उदाहरण व्यक्तिगत स्थिति नहीं है) और उत्परिवर्तनीय या अपरिवर्तनीय का प्रश्न मूक हो जाता है।
सेबस्टियन रेडल

क्या कंस्ट्रक्टर के अलावा अन्य क्षेत्रों को इनिशियलाइज़ करने का कोई अन्य तरीका है। मेरी कक्षा में 20 से अधिक क्षेत्र हैं। कंस्ट्रक्टर का उपयोग करके सभी फ़ील्ड को इनिशियलाइज़ करना बहुत मुश्किल है, कुछ फ़ील्ड्स वैकल्पिक भी हैं।
निखिल मिश्रा

जवाबों:


88

नीचे एक अपरिवर्तनीय वस्तु की कठिन आवश्यकताएं हैं।

  1. कक्षा को अंतिम रूप दें
  2. सभी सदस्यों को अंतिम रूप दें, उन्हें स्पष्ट रूप से, स्थैतिक ब्लॉक में या कंस्ट्रक्टर में सेट करें
  3. सभी सदस्यों को निजी बनाओ
  4. कोई विधियाँ जो राज्य को संशोधित नहीं करती हैं
  5. उत्परिवर्तित सदस्यों तक पहुंच सीमित करने के लिए बेहद सावधान रहें (याद रखें कि फ़ील्ड हो सकता है finalलेकिन ऑब्जेक्ट अभी भी परिवर्तनशील हो सकता है। यानी private final Date imStillMutable)। आपको defensive copiesइन मामलों में बनाना चाहिए ।

कक्षा बनाने के पीछे तर्क finalबहुत सूक्ष्म है और अक्सर अनदेखी की जाती है। यदि इसके अंतिम लोग स्वतंत्र रूप से आपकी कक्षा का विस्तार नहीं कर सकते हैं, तो आपत्तिजनक व्यवहार कर publicसकते protectedहैं, परस्पर गुण जोड़ सकते हैं, फिर उनके उपवर्ग को विकल्प के रूप में आपूर्ति कर सकते हैं। कक्षा को घोषित करके finalआप यह सुनिश्चित कर सकते हैं कि ऐसा नहीं होगा।

कार्रवाई में समस्या को देखने के लिए नीचे दिए गए उदाहरण पर विचार करें:

public class MyApp{

    /**
     * @param args
     */
    public static void main(String[] args){

        System.out.println("Hello World!");

        OhNoMutable mutable = new OhNoMutable(1, 2);
        ImSoImmutable immutable = mutable;

        /*
         * Ahhhh Prints out 3 just like I always wanted
         * and I can rely on this super immutable class 
         * never changing. So its thread safe and perfect
         */
        System.out.println(immutable.add());

        /* Some sneak programmer changes a mutable field on the subclass */
        mutable.field3=4;

        /*
         * Ahhh let me just print my immutable 
         * reference again because I can trust it 
         * so much.
         * 
         */
        System.out.println(immutable.add());

        /* Why is this buggy piece of crap printing 7 and not 3
           It couldn't have changed its IMMUTABLE!!!! 
         */
    }

}

/* This class adheres to all the principles of 
*  good immutable classes. All the members are private final
*  the add() method doesn't modify any state. This class is 
*  just a thing of beauty. Its only missing one thing
*  I didn't declare the class final. Let the chaos ensue
*/ 
public class ImSoImmutable{
    private final int field1;
    private final int field2;

    public ImSoImmutable(int field1, int field2){
        this.field1 = field1;
        this.field2 = field2;
    }

    public int add(){
        return field1+field2;
    }
}

/*
This class is the problem. The problem is the 
overridden method add(). Because it uses a mutable 
member it means that I can't  guarantee that all instances
of ImSoImmutable are actually immutable.
*/ 
public class OhNoMutable extends ImSoImmutable{   

    public int field3 = 0;

    public OhNoMutable(int field1, int field2){
        super(field1, field2);          
    }

    public int add(){
       return super.add()+field3;  
    }

}

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

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


सभी स्थिर सदस्यों के बारे में क्या?
नील सालपे

1
वर्ग को इसके लिए अंतिम होने की आवश्यकता नहीं है।
एंजेल ओ स्फीयर

12
@ निलेश: अपरिवर्तनीयता उदाहरणों की संपत्ति है । स्थैतिक सदस्य आमतौर पर किसी एक उदाहरण से संबंधित नहीं होते हैं, इसलिए वे यहां चित्र में नहीं आते हैं।
जोकिम सॉर

4
जोशुआ बलोच का आइटम 15 अपरिवर्तनीयता पर - कोई भी तरीका जो राज्य को संशोधित नहीं करता है, सभी फ़ील्ड अंतिम, सभी फ़ील्ड निजी, सुनिश्चित करें कि वर्ग बढ़ाया नहीं जा सकता है, किसी भी परिवर्तनशील घटकों तक अनन्य पहुंच सुनिश्चित करें।
nsfyn55

2
@ जौचिम - वे बिल्कुल समीकरण का हिस्सा हैं - ऊपर का उदाहरण लें यदि मैं एक परस्पर स्थिर सदस्य जोड़ता हूं और इसे ImSoImmutable के फ़ंक्शन में उपयोग करता हूं तो आपको वही समस्या है। यदि कोई वर्ग अपरिवर्तनीय है तो सभी पहलुओं को अपरिवर्तनीय होना चाहिए।
nsfyn55

14

बस वर्ग में सार्वजनिक उत्परिवर्ती (सेटर) विधियाँ न जोड़ें।


सभी स्थिर सदस्यों के बारे में क्या? इस प्रकार की वस्तुओं के लिए संदर्भ या वस्तु की स्थिति बदल जाती है?
नील सालपे

7
कोई बात नहीं। यदि आप उन्हें किसी विधि द्वारा बाहरी रूप से नहीं बदल सकते हैं, तो यह अपरिवर्तनीय है।
BalusC

इसका उत्तर नहीं दिया जा सकता है क्योंकि हम नहीं जानते कि स्थैतिक ज्ञापन क्या करते हैं ... ofc वे निजी क्षेत्रों को संशोधित कर सकते हैं। यदि वे ऐसा करते हैं, तो वह वर्ग असाध्य नहीं है।
एंजेल ओ स्फीयर

और क्लास डिफॉल्ट कंस्ट्रक्टर होना चाहिए privateया क्लास होनी चाहिए final। सिर्फ विरासत से बचने के लिए। क्योंकि वंशानुक्रम उल्लंघन का उल्लंघन करता है।
तलहा अहमद खान

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

14

कक्षाएं अपरिवर्तनीय नहीं हैं, वस्तुएं हैं।

अपरिवर्तनीय का अर्थ है: मेरा सार्वजनिक दृश्यमान राज्य प्रारंभिक होने के बाद नहीं बदल सकता है।

फ़ील्ड्स को अंतिम रूप से घोषित करने की आवश्यकता नहीं है, हालांकि यह थ्रेड सुरक्षा सुनिश्चित करने में काफी मदद कर सकता है

यदि आपके पास केवल स्थिर सदस्य हैं, तो इस वर्ग की वस्तुएँ अपरिवर्तनीय हैं, क्योंकि आप उस वस्तु की स्थिति नहीं बदल सकते हैं (आप शायद इसे या तो नहीं बना सकते हैं :))


3
सभी क्षेत्रों को स्थिर बनाने से सभी आवृत्तियों को उसी स्थिति को साझा करने के लिए सीमित किया जाता है जो वास्तव में उपयोगी नहीं है।
अवीद

6

जावा में एक वर्ग को अपरिवर्तनीय बनाने के लिए, आप निम्नलिखित बातों पर ध्यान दे सकते हैं:

1. कक्षा के किसी भी उदाहरण चर के मूल्यों को संशोधित करने के लिए सेटर विधियां प्रदान न करें।

2. वर्ग को 'अंतिम' घोषित करें । यह किसी भी अन्य वर्ग को इसे विस्तारित करने से रोकता है और इसलिए इससे किसी भी तरीके को ओवरराइड करने से रोका जा सकता है जो उदाहरण चर मानों को संशोधित कर सकता है।

3. उदाहरण चर को निजी और अंतिम घोषित करें ।

4. आप के रूप में भी वर्ग के निर्माता घोषणा कर सकते हैं निजी और जरूरत पड़ने पर वर्ग का एक उदाहरण बनाने के लिए एक कारखाने विधि जोड़ें।

इन बिंदुओं की मदद करनी चाहिए !!


3
WRT # 4 कंस्ट्रक्टर विज़िबिल्टी कैसे परस्पर प्रभाव को प्रभावित करता है? स्ट्रिंग अपरिवर्तनीय है, लेकिन कई सार्वजनिक निर्माता हैं।
रयान

जैसा कि @Ryan ने कहा, उदाहरण के चर के लिए भी यही बात लागू होती है: इन्हें घोषित क्यों किया जाना चाहिए private?
एमसी सम्राट

निश्चित नहीं है कि इस उत्तर का कोई प्रभाव क्यों है। यह उत्तर अधूरा है। यह उन उत्परिवर्तित वस्तुओं के बारे में बात नहीं करता है, जिन्हें संबोधित किया जाना महत्वपूर्ण है। कृपया बेहतर समझ के लिए @ nsfyn55 की व्याख्या पढ़ें।
केतन आर

4

से ओरेकल साइट, कैसे जावा में अपरिवर्तनीय वस्तुओं को बनाने के।

  1. "सेटर" विधियाँ उपलब्ध न कराएँ - वे विधियाँ जो फ़ील्ड्स या फ़ील्ड्स द्वारा संदर्भित ऑब्जेक्ट्स को संशोधित करती हैं।
  2. सभी क्षेत्रों को अंतिम और निजी बनाएं।
  3. उपवर्गों को विधियों को ओवरराइड करने की अनुमति न दें। ऐसा करने का सबसे सरल तरीका वर्ग को अंतिम घोषित करना है। एक अधिक परिष्कृत दृष्टिकोण निर्माता को निजी बनाने और कारखाने के तरीकों में उदाहरणों का निर्माण करना है।
  4. यदि उदाहरण फ़ील्ड में परिवर्तनशील वस्तुओं के संदर्भ शामिल हैं, तो उन ऑब्जेक्ट को बदलने की अनुमति न दें:
    I. उन तरीकों को प्रदान न करें जो उत्परिवर्तित वस्तुओं को संशोधित करते हैं।
    द्वितीय। उत्परिवर्तित वस्तुओं का संदर्भ साझा न करें। बाहरी, उत्परिवर्तित वस्तुओं के संदर्भ को कभी भी कंस्ट्रक्टर के पास न रखें; यदि आवश्यक हो, तो प्रतियां बनाएं, और प्रतियां के संदर्भों को संग्रहीत करें। इसी तरह, अपने तरीकों में मूल को वापस करने से बचने के लिए आवश्यक होने पर अपनी आंतरिक परिवर्तनशील वस्तुओं की प्रतियां बनाएं।

3

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

एक अपरिवर्तनीय वस्तु बनाने के लिए आपको कुछ सरल नियमों का पालन करना होगा:

1. किसी भी सेटर विधि को न जोड़ें

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

2. सभी क्षेत्रों को अंतिम और निजी घोषित करें

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

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

3. यदि कोई क्षेत्र एक परिवर्तनशील वस्तु है, तो इसे पाने के तरीकों के लिए रक्षात्मक प्रतियां बनाएं

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

4. यदि कंस्ट्रक्टर को पास की गई एक परिवर्तनशील वस्तु को एक क्षेत्र को सौंपा जाना चाहिए, तो इसकी एक रक्षात्मक प्रतिलिपि बनाई जाएगी

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

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

5. उपवर्गों को तरीकों को ओवरराइड करने की अनुमति न दें

यदि एक उपवर्ग एक विधि को ओवरराइड करता है तो यह एक रक्षात्मक प्रति के बजाय एक परिवर्तनशील क्षेत्र के मूल मूल्य को वापस कर सकता है।

इस समस्या को हल करने के लिए निम्न में से एक करना संभव है:

  1. अपरिवर्तनीय वर्ग को अंतिम घोषित करें ताकि इसे बढ़ाया नहीं जा सके
  2. अपरिवर्तनीय वर्ग के फाइनल के सभी तरीकों की घोषणा करें ताकि उन्हें ओवरराइड नहीं किया जा सके
  3. एक निजी कंस्ट्रक्टर और एक कारखाना बनाएं जो अपरिवर्तनीय वर्ग के उदाहरणों को बनाने के लिए है क्योंकि निजी कंस्ट्रक्टरों के साथ एक वर्ग को बढ़ाया नहीं जा सकता है

यदि आप उन सरल नियमों का पालन करते हैं तो आप धागे के बीच अपनी अपरिवर्तनीय वस्तुओं को स्वतंत्र रूप से साझा कर सकते हैं क्योंकि वे धागे सुरक्षित हैं!

नीचे कुछ उल्लेखनीय बिंदु दिए गए हैं:

  • अपरिवर्तनीय वस्तुएं वास्तव में कई मामलों में जीवन को सरल बनाती हैं। वे विशेष रूप से मूल्य प्रकारों के लिए लागू होते हैं, जहां वस्तुओं की पहचान नहीं होती है, ताकि उन्हें आसानी से बदला जा सके और वे समवर्ती प्रोग्रामिंग तरीका सुरक्षित और साफ-सुथरा बना सकें (अधिकांश कुख्यात कठिनता से खोजने के लिए संगीन कीड़े अंततः उत्परिवर्तित राज्य के बीच साझा किए जाते हैं धागे)। हालांकि, बड़ी और / या जटिल वस्तुओं के लिए, हर एक परिवर्तन के लिए वस्तु की एक नई प्रति बनाना बहुत महंगा और / या थकाऊ हो सकता है । और एक विशिष्ट पहचान वाली वस्तुओं के लिए, मौजूदा वस्तुओं को बदलना एक नई, संशोधित प्रति बनाने से कहीं अधिक सरल और सहज है।
  • कुछ चीजें हैं जो आप अपरिवर्तनीय वस्तुओं के साथ नहीं कर सकते हैं, जैसे द्विदिश संबंध हैं । एक बार जब आप एक वस्तु पर एक संघ मूल्य निर्धारित करते हैं, तो यह पहचान परिवर्तन है। तो, आप नए ऑब्जेक्ट को अन्य ऑब्जेक्ट पर सेट करते हैं और यह भी बदलता है। समस्या यह है कि पहली ऑब्जेक्ट का संदर्भ अब मान्य नहीं है, क्योंकि ऑब्जेक्ट के संदर्भ के साथ प्रतिनिधित्व करने के लिए एक नया उदाहरण बनाया गया है। इसे जारी रखने से अनंत परिणाम प्राप्त होंगे।
  • एक द्विआधारी खोज पेड़ को लागू करने के लिए , आपको हर बार एक नया पेड़ वापस करना होगा: आपके नए पेड़ को प्रत्येक नोड की एक प्रति बनानी होगी जिसे संशोधित किया गया है (संयुक्त राष्ट्र की संशोधित शाखाएं साझा की गई हैं)। आपके इंसर्ट फंक्शन के लिए यह बहुत बुरा नहीं है, लेकिन जब मैं डिलीट और री-बैलेंस पर काम करना शुरू करता हूं तो मेरे लिए चीजें बहुत जल्दी अक्षम हो जाती हैं।
  • हाइबरनेट और जेपीए अनिवार्य रूप से निर्देशित करते हैं कि आपका सिस्टम परस्पर वस्तुओं का उपयोग करता है, क्योंकि उनका पूरा आधार यह है कि वे आपके डेटा ऑब्जेक्ट में परिवर्तनों का पता लगाते हैं और सहेजते हैं।
  • भाषा के आधार पर एक संकलक अपरिवर्तनीय डेटा के साथ काम करते समय अनुकूलन का एक गुच्छा बना सकता है क्योंकि यह जानता है कि डेटा कभी नहीं बदलेगा। सभी प्रकार के सामान को छोड़ दिया गया है, जो आपको जबरदस्त प्रदर्शन लाभ देता है।
  • यदि आप अन्य ज्ञात JVM भाषाओं ( Scala, Clojure ) को देखते हैं, तो उत्परिवर्तनीय वस्तुएं कोड में शायद ही कभी देखी जाती हैं और इसीलिए लोग उन परिदृश्यों में उनका उपयोग करना शुरू करते हैं जहां एकल थ्रेडिंग पर्याप्त नहीं है।

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


2
  • "सेटर" विधियाँ उपलब्ध न कराएँ - वे विधियाँ जो फ़ील्ड्स या फ़ील्ड्स द्वारा संदर्भित ऑब्जेक्ट्स को संशोधित करती हैं।
  • सभी क्षेत्रों को अंतिम और निजी बनाएं।
  • उपवर्गों को विधियों को ओवरराइड करने की अनुमति न दें। ऐसा करने का सबसे सरल तरीका वर्ग को अंतिम घोषित करना है। एक अधिक परिष्कृत दृष्टिकोण निर्माता को निजी बनाने और कारखाने के तरीकों में उदाहरणों का निर्माण करना है।
  • यदि उदाहरण फ़ील्ड में परिवर्तनशील वस्तुओं के संदर्भ शामिल हैं, तो उन वस्तुओं को बदलने की अनुमति न दें:
    • ऐसी विधियाँ प्रदान न करें जो उत्परिवर्तित वस्तुओं को संशोधित करती हैं।
    • उत्परिवर्तित वस्तुओं का संदर्भ साझा न करें। बाहरी, उत्परिवर्तित वस्तुओं के संदर्भ को कभी भी कंस्ट्रक्टर के पास न रखें; यदि आवश्यक हो, तो प्रतियां बनाएं, और प्रतियां के संदर्भों को संग्रहीत करें। इसी तरह, अपने तरीकों में मूल लौटने से बचने के लिए आवश्यक होने पर अपनी आंतरिक परिवर्तनशील वस्तुओं की प्रतियां बनाएं।

2

सबसे पहले, आप जानते हैं कि आपको अपरिवर्तनीय वस्तु बनाने की आवश्यकता क्यों है, और अपरिवर्तनीय वस्तु के क्या फायदे हैं।

एक अपरिवर्तनीय वस्तु के लाभ

समरूपता और मल्टीथ्रेडिंग यह स्वचालित रूप से थ्रेड-सुरक्षित है इसलिए सिंक्रनाइज़ेशन समस्या .... आदि

कंस्ट्रक्टर को कॉपी करने की आवश्यकता नहीं है, क्लोन के कार्यान्वयन की आवश्यकता नहीं है कक्षा को ओवरराइड नहीं किया जा सकता है । क्षेत्र को एक निजी और अंतिम फोर्स कॉलर्स के रूप में बनाएं , एक नो-आर्ग्यूमेंट कंस्ट्रक्टर का उपयोग करने के बजाय एक ही चरण में पूरी तरह से एक ऑब्जेक्ट का निर्माण करने के लिए

अपरिवर्तनीय वस्तुएं केवल ऐसी वस्तुएं हैं जिनके राज्य का अर्थ है कि वस्तु का डेटा अपरिवर्तनीय वस्तु के निर्माण के बाद नहीं बदल सकता है।

कृपया नीचे कोड देखें।

public final class ImmutableReminder{
    private final Date remindingDate;

    public ImmutableReminder (Date remindingDate) {
        if(remindingDate.getTime() < System.currentTimeMillis()){
            throw new IllegalArgumentException("Can not set reminder" +
                    " for past time: " + remindingDate);
        }
        this.remindingDate = new Date(remindingDate.getTime());
    }

    public Date getRemindingDate() {
        return (Date) remindingDate.clone();
    }
}

2

कम से कम परिवर्तनशीलता

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

JDK अपरिवर्तनीय वर्ग: स्ट्रिंग, बॉक्सिंग आदिम वर्ग (आवरण वर्ग), BigInteger और Bigbecal आदि।

कक्षा को अपरिवर्तनीय कैसे बनाया जाए?

  1. ऑब्जेक्ट की स्थिति (म्यूटर्स के रूप में जाना जाता है) को संशोधित करने वाली कोई भी विधि प्रदान न करें।
  2. सुनिश्चित करें कि कक्षा को बढ़ाया नहीं जा सकता।
  3. सभी क्षेत्रों को अंतिम रूप दें।
  4. सभी क्षेत्रों को निजी बनाएं। यह क्लाइंट को फ़ील्ड द्वारा संदर्भित उत्परिवर्तनीय वस्तुओं तक पहुंच प्राप्त करने और इन वस्तुओं को सीधे संशोधित करने से रोकता है।
  5. रक्षात्मक प्रतियां बनाएं। किसी भी परिवर्तनशील घटकों के लिए विशेष पहुंच सुनिश्चित करें।

    सार्वजनिक सूची getList () {Return Collections.unmodifiableList (सूची); <=== कॉल करने वाले को वापस करने से पहले उत्परिवर्तित फ़ील्ड की रक्षात्मक प्रतिलिपि}

यदि आपकी कक्षा में कोई भी फ़ील्ड है जो परस्पर वस्तुओं को संदर्भित करता है, तो सुनिश्चित करें कि वर्ग के ग्राहक इन वस्तुओं के संदर्भ प्राप्त नहीं कर सकते हैं। कभी भी ऐसे क्षेत्र को क्लाइंट-प्रदान की गई ऑब्जेक्ट संदर्भ में इनिशियलाइज़ न करें या एक्सेसर से ऑब्जेक्ट रेफ़रेंस लौटाएँ।

import java.util.Date;
public final class ImmutableClass {

       public ImmutableClass(int id, String name, Date doj) {
              this.id = id;
              this.name = name;
              this.doj = doj;
       }

       private final int id;
       private final String name;
       private final Date doj;

       public int getId() {
              return id;
       }
       public String getName() {
              return name;
       }

     /**
      * Date class is mutable so we need a little care here.
      * We should not return the reference of original instance variable.
      * Instead a new Date object, with content copied to it, should be returned.
      * */
       public Date getDoj() {
              return new Date(doj.getTime()); // For mutable fields
       }
}
import java.util.Date;
public class TestImmutable {
       public static void main(String[] args) {
              String name = "raj";
              int id = 1;
              Date doj = new Date();

              ImmutableClass class1 = new ImmutableClass(id, name, doj);
              ImmutableClass class2 = new ImmutableClass(id, name, doj);
      // every time will get a new reference for same object. Modification in              reference will not affect the immutability because it is temporary reference.
              Date date = class1.getDoj();
              date.setTime(date.getTime()+122435);
              System.out.println(class1.getDoj()==class2.getDoj());
       }
}

अधिक जानकारी के लिए, मेरा ब्लॉग देखें:
http://javaexplorer03.blogspot.in/2015/07/minimize-ututut.html


@ पंगड़ कंस्ट्रक्टर के अलावा अन्य क्षेत्रों को इनिशियलाइज़ करने का कोई अन्य तरीका है। मेरी कक्षा में 20 से अधिक क्षेत्र हैं। कंस्ट्रक्टर का उपयोग करके सभी फ़ील्ड को इनिशियलाइज़ करना बहुत मुश्किल है, कुछ फ़ील्ड्स वैकल्पिक भी हैं।
निखिल मिश्रा

1
@ निखिलमिश्रा, आप ऑब्जेक्ट कंस्ट्रक्शन के दौरान वैरिएबल को इनिशियलाइज़ करने के लिए बिल्डर डिज़ाइन पैटर्न का उपयोग कर सकते हैं। आप कंस्ट्रक्टर में सेट किए जाने के लिए अनिवार्य चर रख सकते हैं और शेष वैकल्पिक चर को सेटर विधियों का उपयोग करके सेट किया जा सकता है। लेकिन इस तरह से सख्ती से बोलने से आप एक सच्चा अपरिवर्तनीय वर्ग नहीं बना पाएंगे।
सनी_देव

1

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


यह नहीं है कि एक प्रति लौटाने की सलाह दी जाती है, इसकी आवश्यक है। लेकिन यह भी आवश्यक है कि कंस्ट्रक्टर में एक रक्षात्मक प्रतिलिपि बनाई गई है। अन्यथा पर्दे के पीछे वस्तु को बदला जा सकता है।
रयान

1

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

अपरिवर्तनीय वर्गों की विशेषताएं:

  • निर्माण करने के लिए सरल है
  • स्वचालित रूप से सुरक्षित धागा
  • मैप कीज के लिए अच्छा उम्मीदवार और प्रसंस्करण के दौरान उनकी आंतरिक स्थिति के रूप में सेट नहीं बदलेगा
  • क्लोन के कार्यान्वयन की आवश्यकता नहीं है क्योंकि वे हमेशा एक ही राज्य का प्रतिनिधित्व करते हैं

अपरिवर्तनीय वर्ग लिखने की कुंजी:

  • सुनिश्चित करें कि वर्ग को ओवरराइड नहीं किया जा सकता है
  • सभी सदस्य चर को निजी और अंतिम बनाएं
  • उनके सेटर के तरीके न दें
  • निर्माण चरण के दौरान ऑब्जेक्ट संदर्भ को लीक नहीं किया जाना चाहिए

1

निम्नलिखित कुछ चरणों पर विचार किया जाना चाहिए, जब आप किसी भी वर्ग को एक अपरिवर्तनीय वर्ग के रूप में चाहते हैं।

  1. कक्षा को अंतिम रूप में चिह्नित किया जाना चाहिए
  2. सभी क्षेत्र निजी और अंतिम होने चाहिए
  3. निर्माता के साथ बसने की जगह (एक चर के लिए एक मूल्य निर्दिष्ट करने के लिए)।

हमने ऊपर जो टाइप किया है, उस पर एक नज़र डालते हैं:

//ImmutableClass
package younus.attari;

public final class ImmutableExample {

    private final String name;
    private final String address;

    public ImmutableExample(String name,String address){
        this.name=name;
        this.address=address;
    }


    public String getName() {
        return name;
    }

    public String getAddress() {
        return address;
    }

}

//MainClass from where an ImmutableClass will be called
package younus.attari;

public class MainClass {

    public static void main(String[] args) {
        ImmutableExample example=new ImmutableExample("Muhammed", "Hyderabad");
        System.out.println(example.getName());

    }
}

0

अपरिवर्तनीय वस्तुओं पर सामान्य रूप से अनदेखा लेकिन महत्वपूर्ण गुण

@ Nsfyn55 द्वारा दिए गए उत्तर पर जोड़ते हुए, वस्तु अपरिवर्तनीयता के लिए निम्नलिखित पहलुओं पर भी विचार करने की आवश्यकता है, जो कि प्रमुख महत्व के हैं

निम्नलिखित वर्गों पर विचार करें:

public final class ImmutableClass {

  private final MutableClass mc;

  public ImmutableClass(MutableClass mc) {
    this.mc = mc;
  }

  public MutableClass getMutClass() {
    return this.mc;
  }
}

public class MutableClass {

  private String name;

  public String getName() {
    return this.name;
  }

  public void setName(String name) {
    this.name = name;
  }
}


public class MutabilityCheck {

public static void main(String[] args) {

  MutableClass mc = new MutableClass();

  mc.setName("Foo");

  ImmutableClass iMC = new ImmutableClass(mc);

  System.out.println(iMC.getMutClass().getName());

  mc.setName("Bar");

  System.out.println(iMC.getMutClass().getName());

  }

 }

निम्नलिखित MutabilityCheck से उत्पादन होगा:

 Foo
 Bar

यह ध्यान रखने के लिए महत्वपूर्ण है,

  1. एक अपरिवर्तनीय वस्तु पर (कंस्ट्रक्टर के माध्यम से) परिवर्तनशील वस्तुओं का निर्माण, निम्नलिखित परिवर्तनों द्वारा वर्णित अपरिवर्तनीय के चर को 'कॉपी' या 'क्लोकिंग' द्वारा:

    public final class ImmutableClass {
    
       private final MutableClass mc;
    
       public ImmutableClass(MutableClass mc) {
         this.mc = new MutableClass(mc);
       }
    
       public MutableClass getMutClass() {
         return this.mc;
       }
    
     }
    
     public class MutableClass {
    
      private String name;
    
      public MutableClass() {
    
      }
      //copy constructor
      public MutableClass(MutableClass mc) {
        this.name = mc.getName();
      }
    
      public String getName() {
        return this.name;
      }
    
      public void setName(String name) {
       this.name = name;
      } 
     }
    

अभी भी पूर्ण अपरिवर्तनीयता सुनिश्चित नहीं करता है क्योंकि निम्नलिखित वर्ग अभी भी वर्गीयता से मान्य है:

  iMC.getMutClass().setName("Blaa");
  1. हालाँकि, 1. में किए गए बदलाव के साथ MutabilityCheck चलाने के परिणामस्वरूप आउटपुट होगा:

    Foo
    Foo
    
  2. किसी वस्तु पर पूर्ण अपरिवर्तनीयता प्राप्त करने के लिए, उसकी सभी आश्रित वस्तुओं को भी अपरिवर्तनीय होना चाहिए


0

JDK 14+ से जिसमें JEP 359 है , हम " records" का उपयोग कर सकते हैं । यह इम्यूटेबल क्लास बनाने का सबसे सरल और ऊधम मुक्त तरीका है।

एक रिकॉर्ड क्लास एक उथली अपरिवर्तनीय , पारदर्शी वाहक है जिसे रिकॉर्ड के रूप में जाना जाता है फ़ील्ड के एक निश्चित सेट के लिए जो रिकॉर्ड के लिए विवरण componentsप्रदान करता है state। प्रत्येक componentएक finalफ़ील्ड को जन्म देता है जो प्रदान किए गए मूल्य और मूल्य accessorको पुनः प्राप्त करने का एक तरीका रखता है । फ़ील्ड नाम और एक्सेसर नाम घटक के नाम से मेल खाते हैं।

आइए एक अपरिवर्तनीय आयत बनाने के उदाहरण पर विचार करें

record Rectangle(double length, double width) {}

किसी भी निर्माता को घोषित करने की आवश्यकता नहीं है, कार्यान्वयन equalsऔर hashCodeविधियों की आवश्यकता नहीं है । बस किसी भी रिकॉर्ड के लिए नाम और राज्य का विवरण चाहिए।

var rectangle = new Rectangle(7.1, 8.9);
System.out.print(rectangle.length()); // prints 7.1

यदि आप ऑब्जेक्ट निर्माण के दौरान मान को मान्य करना चाहते हैं, तो हमें स्पष्ट रूप से निर्माता को घोषित करना होगा।

public Rectangle {

    if (length <= 0.0) {
      throw new IllegalArgumentException();
    }
  }

रिकॉर्ड का शरीर स्थिर विधियों, स्थिर क्षेत्रों, स्थिर आरंभीकरण, निर्माणकर्ताओं, उदाहरण विधियों, और नेस्टेड प्रकारों की घोषणा कर सकता है।

उदाहरण के तरीके

record Rectangle(double length, double width) {

  public double area() {
    return this.length * this.width;
  }
}

स्थिर क्षेत्र, विधियाँ

चूंकि राज्य घटकों का हिस्सा होना चाहिए इसलिए हम रिकॉर्ड में फ़ील्ड जोड़ नहीं सकते हैं। लेकिन, हम स्थैतिक क्षेत्रों और विधियों को जोड़ सकते हैं:

record Rectangle(double length, double width) {

  static double aStaticField;

  static void aStaticMethod() {
    System.out.println("Hello Static");
  }
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.