अपरिवर्तनीय बनाम अनम्य संग्रह


170

से संग्रह फ्रेमवर्क अवलोकन :

ऐसे संग्रह जो संशोधन कार्यों का समर्थन नहीं करते हैं (जैसे कि add, removeऔर clear) को अस्वीकार्य कहा जाता है । ऐसे संग्रह जो अप्रमाणिक नहीं हैं, वे परिवर्तनीय हैं

ऐसे संग्रह जो अतिरिक्त गारंटी देते हैं कि Collectionऑब्जेक्ट में कोई परिवर्तन दिखाई नहीं देगा, को अपरिवर्तनीय कहा जाता है । संग्रह जो अपरिवर्तनीय नहीं हैं, वे पारस्परिक हैं

मैं भेद नहीं समझ सकता।
बीच क्या अंतर है unmodifiable और अपरिवर्तनीय यहाँ?

जवाबों:


207

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

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

मूल रूप से, अंतर यह है कि क्या अन्य कोड आपकी पीठ के पीछे संग्रह को बदलने में सक्षम हो सकता है।


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

8
@HieryNomus: ध्यान दें कि मैंने यह नहीं कहा कि कुछ भी नहीं बदल सकता है - मैंने कहा कि कुछ भी संग्रह को नहीं बदल सकता है।
जॉन स्कीट

1
ठीक है, हो सकता है कि गलतफहमी हुई हो;) लेकिन इसे स्पष्ट करना अच्छा है।
हायरी नोमस

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

1
@savanibharat: यह इस बात पर निर्भर करता है कि क्या कोई कोड पथ है जो अभी भी संशोधित कर सकता है list। अगर कुछ बाद में कॉल कर सकता है list.add(10)तो collउस बदलाव को प्रतिबिंबित करेगा, इसलिए नहीं, मैं इसे अपरिवर्तनीय नहीं कहूंगा।
जॉन स्कीट

92

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

हालाँकि immutableसंग्रह को दूसरे संग्रह की एक प्रतिलिपि के रूप में माना जा सकता है और इसे संशोधित नहीं किया जा सकता है। इस स्थिति में जब स्रोत संग्रह बदलता है, तो अपरिवर्तनीय संग्रह परिवर्तनों को प्रतिबिंबित नहीं करता है

इस अंतर की कल्पना करने के लिए यहां एक टेस्टकेस है।

@Test
public void testList() {

    List<String> modifiableList = new ArrayList<String>();
    modifiableList.add("a");

    System.out.println("modifiableList:"+modifiableList);
    System.out.println("--");


    //unModifiableList

    assertEquals(1, modifiableList.size());

    List<String> unModifiableList=Collections.unmodifiableList(
                                        modifiableList);

    modifiableList.add("b");

    boolean exceptionThrown=false;
    try {
        unModifiableList.add("b");
        fail("add supported for unModifiableList!!");
    } catch (UnsupportedOperationException e) {
        exceptionThrown=true;
        System.out.println("unModifiableList.add() not supported");
    }
    assertTrue(exceptionThrown);

    System.out.println("modifiableList:"+modifiableList);
    System.out.println("unModifiableList:"+unModifiableList);

    assertEquals(2, modifiableList.size());
    assertEquals(2, unModifiableList.size());
            System.out.println("--");



            //immutableList


    List<String> immutableList=Collections.unmodifiableList(
                            new ArrayList<String>(modifiableList));

    modifiableList.add("c");

    exceptionThrown=false;
    try {
        immutableList.add("c");
        fail("add supported for immutableList!!");
    } catch (UnsupportedOperationException e) {
        exceptionThrown=true;
        System.out.println("immutableList.add() not supported");
    }
    assertTrue(exceptionThrown);


    System.out.println("modifiableList:"+modifiableList);
    System.out.println("unModifiableList:"+unModifiableList);
    System.out.println("immutableList:"+immutableList);
    System.out.println("--");

    assertEquals(3, modifiableList.size());
    assertEquals(3, unModifiableList.size());
    assertEquals(2, immutableList.size());

}

उत्पादन

modifiableList:[a]
--
unModifiableList.add() not supported
modifiableList:[a, b]
unModifiableList:[a, b]
--
immutableList.add() not supported
modifiableList:[a, b, c]
unModifiableList:[a, b, c]
immutableList:[a, b]
--

मैं कोई अंतर नहीं देख पा रहा हूं, क्या आप कृपया बता सकते हैं कि कैसे अपरिवर्तनीय है? मैं देख सकता हूं कि अपरिवर्तनीय और अपरिवर्तनीय दोनों त्रुटि फेंक रहे हैं और जोड़ समर्थित नहीं है। क्या मुझसे कोई चूक हो रही है?
एकेएस

2
@AK कृपया सूची में 'ग' के अलावा पिछली तीन सूची प्रविष्टियों का उत्पादन देखें, जबकि आकार में वृद्धि हुई है modifiableListऔर दोनों का आकार नहीं बदला हैunModifiableListimmutableList
प्रशांत भाटे

1
ओह! समझ गया! :) .. तो यहाँ पर आपने modifiableList में परिवर्तन का उपयोग करते हुए unmodifableList को संशोधित किया है, लेकिन ImmutableList को संशोधित नहीं किया जा सकता है। लेकिन इसी तरह से आप ImmutableList को भी संशोधित कर सकते हैं, मुझे लगता है कि यहाँ ग्राहक को केवल ImmutableList संदर्भ तक पहुँच प्राप्त होगी, modifiableList के संदर्भ में, जिसका उपयोग करके ImmutableList बनाया जाता है, ग्राहक के सामने नहीं आएगा। सही?
एकेएस

1
हां क्योंकि new ArrayList<String>(modifiableList)अपरिवर्तनीय का कोई संदर्भ नहीं है, संशोधित नहीं किया जा सकता है
प्रशांत भाटे

@PrashantBhate नमस्ते, के कारण कोई संदर्भ नहीं new ArrayList<String>(modifiableList)है new? धन्यवाद।
उन्हेलिग

11

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

ओरेकल के जावा कलेक्शन रैपर ट्यूटोरियल में यह कहना है (जोर जोड़ा गया):

निम्न प्रकार से असंशोधित आवरणों के दो मुख्य उपयोग हैं:

  • एक बार संग्रहित होने के बाद इसे बनाए रखने के लिए। इस मामले में, बैकिंग संग्रह के संदर्भ को बनाए रखने के लिए अच्छा नहीं है। यह बिल्कुल अपरिवर्तनीयता की गारंटी देता है।
  • कुछ क्लाइंट को केवल आपके डेटा स्ट्रक्चर्स तक पढ़ने की अनुमति देने के लिए। आप बैकिंग संग्रह के लिए एक संदर्भ रखते हैं लेकिन आवरण के संदर्भ को सौंप देते हैं। इस तरह, ग्राहक पूर्ण पहुंच बनाए रखते हुए, संशोधित नहीं बल्कि देख सकते हैं

3

अगर हम JDK Unmodifiable*बनाम अमरूद के बारे में बात कर रहे हैं Immutable*, वास्तव में अंतर प्रदर्शन में भी है । अपरिवर्तनीय संग्रह दोनों तेज और अधिक स्मृति-कुशल हो सकते हैं यदि वे नियमित संग्रह के आसपास रैपर नहीं हैं (JDK कार्यान्वयन रैपर हैं)। अमरूद टीम का हवाला देते हुए :

JDK, कलेक्शंस .unmodifiableXXX तरीके प्रदान करता है, लेकिन हमारी राय में, ये हो सकते हैं

<...>

  • अकुशल: डेटा संरचनाओं में अभी भी परिवर्तनशील संग्रह के सभी ओवरहेड हैं, जिनमें समवर्ती संशोधन जांच, हैवी टेबल में अतिरिक्त स्थान आदि शामिल हैं।

प्रदर्शन के बारे में सोचते हुए, आपको यह भी ध्यान रखना चाहिए कि एक अनमॉडिफ़ेबल रैपर कलेक्शन को कॉपी नहीं करता है, जहाँ अमरुद में इस्तेमाल होने वाले अपरिवर्तनीय संस्करण के रूप में और अब jdk9 + में भी जैसे List.of(...)कि वास्तव में दो बार कॉपी होता है!
बेनेज़

2

जावा ™ ट्यूटोरियल उद्धृत करने के लिए :

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

  • एक बार संग्रहित होने के बाद इसे बनाए रखने के लिए। इस मामले में, बैकिंग संग्रह के संदर्भ को बनाए रखने के लिए अच्छा नहीं है। यह बिल्कुल अपरिवर्तनीयता की गारंटी देता है।

  • कुछ ग्राहकों को केवल आपकी डेटा संरचनाओं तक पढ़ने की अनुमति देने के लिए। आप बैकिंग संग्रह के लिए एक संदर्भ रखते हैं लेकिन आवरण के संदर्भ को सौंप देते हैं। इस तरह, ग्राहक पूर्ण पहुंच बनाए रखते हुए, संशोधित नहीं बल्कि देख सकते हैं।

(जोर मेरा)

यह वास्तव में इसे बोता है।


1

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

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

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

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


1

जावा ™ ट्यूटोरियल निम्नलिखित कहते हैं:

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

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

कुछ ग्राहकों को केवल आपकी डेटा संरचनाओं तक पढ़ने की अनुमति देने के लिए। आप बैकिंग संग्रह के लिए एक संदर्भ रखते हैं लेकिन आवरण के संदर्भ को सौंप देते हैं। इस तरह, ग्राहक पूर्ण पहुंच बनाए रखते हुए, संशोधित नहीं बल्कि देख सकते हैं।

मुझे लगता है कि इसका अंतर समझने के लिए एक अच्छी पर्याप्त व्याख्या है।

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