2011-05-26 43 views
14

मुझे विभिन्न सदस्य चर के साथ एक वर्ग मिला है। एक कन्स्ट्रक्टर है और गेट-विधियां हैं, लेकिन कोई सेटटर-विधियां नहीं हैं। वास्तव में, यह वस्तु अपरिवर्तनीय होना चाहिए।ArrayList सदस्य चर के साथ अपरिवर्तनीय वस्तु - यह चर क्यों बदला जा सकता है?

public class Example { 
    private ArrayList<String> list; 
} 

अब मैं निम्नलिखित देखा: जब मैं एक गेटर-विधि के साथ चर सूची मिलता है, मैं नए मूल्यों और इतने पर जोड़ सकते हैं - मैं ArrayList बदल सकते हैं। जब मैं इस चर के लिए अगली बार get() पर कॉल करता हूं, तो ArrayList बदल दिया जाता है। यह कैसे हो सकता है? मैंने इसे फिर से सेट नहीं किया, मैंने अभी इस पर काम किया! String के साथ यह व्यवहार संभव नहीं है। तो यहाँ क्या अंतर है?

उत्तर

35

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

यहां तक ​​कि अगर listfinal बनाया गया था इस

// changing the object which list refers to 
example.getList().add("stuff"); 

की अनुमति दी जाएगी, लेकिन इस अनुमति नहीं होगा:

// changing list 
example.list = new ArrayList<String>(); // assuming list is public 

क्रम सूची अपरिवर्तनीय बनाने के लिए (यह भी रोकने के पहली पंक्ति), मेरा सुझाव है कि आप Collections.unmodifiableList का उपयोग करें:

public class Example { 
    final private ArrayList<String> list; 

    Example(ArrayList<String> listArg) { 
     list = Collections.unmodifiableList(listArg); 
    } 
} 

(ध्यान दें कि यह सूची का एक अपरिहार्य दृश्य बनाता है। किसी मूल संदर्भ को पकड़ने में है, तो सूची में अभी भी उस के माध्यम से संभव नहीं है इस व्यवहार को संशोधित किया जा सकता है।)


एक तार के साथ। तो यहाँ क्या अंतर है?

है ऐसा इसलिए है क्योंकि एक String पहले से ही अपरिवर्तनीय (unmodifiable) बस के रूप में सूची यदि आप इसे एक unmodifiableList में बदल गया होगा।

तुलना:

   String data structure | List data structure 
      .-------------------------+------------------------------------. 
Immutable | String     | Collection.unmodifiableList(...) | 
-----------+-------------------------+------------------------------------| 
Mutable | StringBuffer   | ArrayList       | 
      '-------------------------+------------------------------------' 
+0

AFAIK की तरह वास्तविक सरणी सूची 'Collections.unmodifiableList()' दी गई सूची के लिए एक अपरिवर्तनीय आवरण रिटर्न ArrayList के प्रति वापस जाने के लिए है। यदि मैं सही हूं, तो उपरोक्तता की गारंटी नहीं होगी। एक वर्ग एक सूची को तुरंत चालू कर सकता है, उदाहरण को तत्काल बना सकता है, और अभी भी उस सूची को संशोधित कर सकता है जो कि निर्माता को मूल सूची को संशोधित करके संशोधित कर रहा है।हालांकि मतभेदों को हल करने के लिए उत्तर पर्याप्त हो सकता है, यह सख्त "अपरिवर्तनीयता" आवश्यकताओं को पूरा करने में विफल हो सकता है। – Maurice

+2

यह सही है। उत्तर अपडेट किया गया। आप 'संग्रह .unmodifiableList (नया ArrayList <> (listArg))' यह सुनिश्चित करने के लिए कर सकते हैं कि कोई भी अंतर्निहित म्यूटेबल सूची का संदर्भ नहीं रखता है और इस प्रकार उत्परिवर्तन से बचता है। – aioobe

15

आप list के संदर्भ में लौट रहे हैं। और list अपरिवर्तनीय नहीं है।


आप अपनी सूची में नहीं करना चाहते हैं इसकी एक प्रति लौट परिवर्तित करने की:

public List<String> get() { 
    return new ArrayList<String>(this.list); 
} 

या आप लौट सकते हैं एक unmodifiable list:

public List<String> get() { 
    return Collections.unmodifiableList(this.list); 
} 
3

कुंजी को समझने के लिए है कि आप नहीं बदल रहे हैं स्ट्रिंग है - आप बदल रहे हैं जो स्ट्रिंग सूची का संदर्भ शामिल हैं।

इसे एक और तरीका रखने के लिए: यदि मैं अपने वॉलेट से डॉलर निकालता हूं, और इसे एक डाइम से बदलता हूं, तो मैंने डॉलर या डाइम को नहीं बदला है - मैंने अभी आपके वॉलेट की सामग्री बदल दी है।

यदि आप सूची में केवल पढ़ने के लिए चाहते हैं, तो Collections.unmodifiableList पर देखें। यह सूची को बंद नहीं करेगा कि यह को पाठ्यक्रम बदलने से लपेटता है, लेकिन यह किसी भी व्यक्ति को रोक देगा जो सामग्री को संशोधित करने से केवल अपरिवर्तनीय सूची का संदर्भ रखता है।

एक सही मायने में अपरिवर्तनीय सूची के लिए, Guava के ImmutableList वर्ग को देखो।

0

इसलिए यदि आप इसे बदलने से बचाने के लिए चाहते हैं तो आपको सूची के लिए गेटटर विधि प्रदान नहीं करनी चाहिए।

इसकी ऑब्जेक्ट्स अभी भी बरकरार रह रही हैं क्योंकि आपके पास सेटर्स नहीं थे। लेकिन आप जो करते हैं वह नई/अलग-अलग वस्तुओं को हटा/जोड़ता है और यह ठीक है।

2

जैसा कि अन्य उत्तरों कहते हैं कि ऑब्जेक्ट्स जो आप गेटर्स से लौटते हैं वह अभी भी परिवर्तनीय है।

list = Collections.unmodifiableList(list); 

आप ग्राहकों को यह वापसी अगर वे इसे करने के लिए जोड़ सकते हैं या तत्वों को दूर करने में सक्षम नहीं होगा:

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

0

सूची संदर्भ अपरिवर्तनीय है, लेकिन सूची नहीं है। यदि आप सूची को अपरिवर्तनीय मानना ​​चाहते हैं, तो ImmutableList

2

संग्रह .unmodifiableList() सूची को अविश्वसनीय बनाता है। जो फिर से एक नई अंतिम सरणी सूची बनाता है और असमर्थित ऑपरेशन अपवाद को फेंकने के लिए विधि को जोड़ने, निकालने, जोड़ने और साफ़ करने के लिए ओवरराइड करता है। यह संग्रह वर्ग का एक हैक। लेकिन संकलन समय पर यह आपको सामान जोड़ने और हटाने से नहीं रोकता है। मैं उस सूची के क्लोनिंग के साथ जाना चाहूंगा। जो मेरी मौजूदा वस्तु को अपरिवर्तनीय रखने में मेरी मदद कर सकता है और मुझे नई सूची बनाने की लागत नहीं है। क्लोनिंग और नए ऑपरेटर (http://www.javatpoint.com/object-cloning) के बीच अंतर पढ़ें। रनटाइम पर भी मेरे कोड को क्रैश करने में मदद मिलेगी।

0

वास्तव में अपरिवर्तनीय सूची प्राप्त करने के लिए, आपको सूची की सामग्री की गहरी प्रतियां बनाना होगा। UnmodifiableList केवल संदर्भों की सूची कुछ हद तक अपरिवर्तनीय प्रस्तुत करेगा। अब सूची या सरणी की गहरी प्रतिलिपि बनाना बढ़ते आकार के साथ स्मृति पर कठिन होगा। आप धारावाहिक/deserialization का उपयोग कर सकते हैं और सरणी/सूची की गहरी प्रति एक temp फ़ाइल में स्टोर कर सकते हैं। सेटर उपलब्ध नहीं होगा क्योंकि सदस्य व्यवहार्यता अपरिवर्तनीय होने की आवश्यकता है। गेटटर सदस्य चर को एक फ़ाइल में क्रमबद्ध करेगा और फिर गहरी प्रति प्राप्त करने के लिए इसे विलुप्त कर देगा। Seraialization एक वस्तु पेड़ की गहराई में जाने की एक सहज प्रकृति है। यह हालांकि कुछ प्रदर्शन लागत पर पूर्ण अपरिवर्तनीयता सुनिश्चित करेगा।

package com.home.immutable.serial; 

import java.io.File; 
import java.io.FileInputStream; 
import java.io.FileNotFoundException; 
import java.io.FileOutputStream; 
import java.io.IOException; 
import java.io.ObjectInputStream; 
import java.io.ObjectOutputStream; 

public final class ImmutableBySerial { 

    private final int num; 
    private final String str; 
    private final TestObjSerial[] arr; 

    ImmutableBySerial(int num, String str, TestObjSerial[] arr){ 
     this.num = num; 
     this.str = str; 
     this.arr = getDeepCloned(arr); 
    } 

    public int getNum(){ 
     return num; 
    } 

    public String getStr(){ 
     return str; 
    } 

    public TestObjSerial[] getArr(){ 
     return getDeepCloned(arr); 
    } 

    private TestObjSerial[] getDeepCloned(TestObjSerial[] arr){ 
     FileOutputStream fos = null; 
     ObjectOutputStream oos = null; 
     FileInputStream fis = null; 
     ObjectInputStream ois = null; 
     TestObjSerial[] clonedObj = null; 
     try { 
      fos = new FileOutputStream(new File("temp")); 
      oos = new ObjectOutputStream(fos); 
      oos.writeObject(arr); 
      fis = new FileInputStream(new File("temp")); 
      ois = new ObjectInputStream(fis); 
      clonedObj = (TestObjSerial[])ois.readObject(); 

     } catch (FileNotFoundException e) { 
      e.printStackTrace(); 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } catch (ClassNotFoundException e) { 
      e.printStackTrace(); 
     } finally { 
      try { 
       oos.close(); 
       fos.close(); 
      } catch (IOException e) { 
       e.printStackTrace(); 
      } 
     } 
     return clonedObj; 
    } 
} 
0

एक अन्य समाधान नहीं इस कोड

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

public final class ImmutableExample { 

    private final List<String> strings = new ArrayList<String>(); 

    public ImmutableExample() { 
     strings.add("strin 1"); 
     strings.add("string 2"); 
    } 

    public List<String> getStrings() { 
     List<String> newStrings = new ArrayList<String>(); 
     strings.forEach(s -> newStrings.add(s)); 
     return newStrings; 
    } 

    public static void main(String[] args) { 
     // TODO Auto-generated method stub 
     ImmutableExample im = new ImmutableExample(); 
     System.out.println(im.getStrings()); 
     im.getStrings().add("string 3"); 
     System.out.println(im.getStrings()); 

    } 
} 
+0

यह नई जानकारी नहीं जोड़ता है। एक प्रतिलिपि को इस उत्तर में समझाया गया है: https://stackoverflow.com/a/6137267 और यह सूची की प्रतिलिपि बनाने के _much_ क्लीनर संस्करण का भी उपयोग करता है। – Tom

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

  • कोई संबंधित समस्या नहीं^_^