जावा कलेक्शंस लिस्ट को कॉपी कैसे करें


141

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

मान लीजिए कि मेरे पास निम्नलिखित हैं:

List<String> a = new ArrayList<String>();
a.add("a");
a.add("b");
a.add("c");
List<String> b = new ArrayList<String>(a.size());

Collections.copy(b,a);

यह विफल रहता है क्योंकि मूल रूप से यह सोचता bहै कि पकड़ के लिए पर्याप्त बड़ा नहीं है a। हां मुझे पता है bकि आकार 0 है, लेकिन यह काफी बड़ा होना चाहिए अब इसे नहीं करना चाहिए? अगर मुझे bपहले भरना है , तो Collections.copy()मेरे दिमाग में पूरी तरह से बेकार कार्य हो जाएगा। तो, एक कॉपी फ़ंक्शन (जो मैं अब करने जा रहा हूं) को प्रोग्रामिंग करने के अलावा, क्या ऐसा करने का एक उचित तरीका है?


डॉक्स फॉर कलेक्शंस.कॉपी () कहती है "गंतव्य सूची कम से कम तब तक होनी चाहिए जब तक स्रोत सूची में है।"
डीजेकेवर्थ

21
मुझे नहीं लगता कि स्वीकृत उत्तर सही है
Bozho

3
आपने गलत जवाब दिया, जैस्पर फ्लोर। मुझे पूरी उम्मीद है कि आपने अपने कोड में गलत जानकारी का उपयोग नहीं किया होगा!
माल्कम

जवाबों:


115

कॉलिंग

List<String> b = new ArrayList<String>(a);

aभीतर उथली नकल बनाता है b। सभी तत्व bउसी क्रम में मौजूद रहेंगे, जो उनके भीतर थे a(यह मानते हुए कि यह एक आदेश था)।

इसी तरह, बुला रहा है

// note: instantiating with a.size() gives `b` enough capacity to hold everything
List<String> b = new ArrayList<String>(a.size());
Collections.copy(b, a);

aभीतर एक उथली प्रति भी बनाता है b। यदि पहला पैरामीटर, bमें पर्याप्त क्षमता (आकार नहीं) है, जिसमें सभी aतत्व शामिल हैं, तो यह एक फेंक देगा IndexOutOfBoundsException। उम्मीद यह है कि Collections.copyकाम करने के लिए किसी भी आवंटन की आवश्यकता नहीं होगी , और यदि कोई हो, तो यह उस अपवाद को फेंकता है। यह प्रचारित करने के लिए कॉपी किए गए संग्रह की आवश्यकता के लिए एक अनुकूलन है b

एक गहरी प्रतिलिपि बनाने के लिए List, या तो तंत्र के माध्यम से, अंतर्निहित प्रकार का जटिल ज्ञान होना चाहिए। Stringएस के मामले में , जो जावा (और उस मामले के लिए .NET) में अपरिवर्तनीय हैं, आपको गहरी कॉपी की भी आवश्यकता नहीं है। के मामले में MySpecialObject, आपको यह जानना होगा कि इसकी गहरी प्रतिलिपि कैसे बनाई जाए और यह एक सामान्य ऑपरेशन नहीं है।


नोट: मूल रूप से स्वीकृत उत्तर Collections.copyGoogle के लिए शीर्ष परिणाम था, और यह गलत था जैसा कि टिप्पणियों में बताया गया था।


1
@nasasas हाँ यह करता है। मैं इस तथ्य को विलाप कर रहा हूं कि जावा में एक सामान्य "कॉपी" फ़ंक्शन नहीं है। व्यवहार में, सभी अक्सर मुझे लगता है कि अन्य लेखकों ने अपनी कक्षाओं के लिए क्लोन () को लागू नहीं किया है; यह किसी वस्तु की किसी भी प्रकार की नकल करने की क्षमता के बिना एक को छोड़ देता है। या, इससे भी बदतर, मैं या तो बिना या खराब प्रलेखन के साथ एक कार्यान्वित क्लोन विधि देखता हूं, जो क्लोन फ़ंक्शन को अनुपयोगी बनाता है (एक विश्वसनीय और व्यावहारिक "यह जानकर कि क्या हो रहा है" समझ में आता है)।
मैल्कम

133

bएक है क्षमता 3 की है, लेकिन एक आकार 0. तथ्य यह है कि के ArrayListइसका हिस्सा नहीं है - है बफर क्षमता किसी प्रकार का एक कार्यान्वयन विस्तार है Listइंटरफेस है, तो Collections.copy(List, List)इसका इस्तेमाल नहीं करता है। यह विशेष मामले के लिए यह बदसूरत होगा ArrayList

जैसा कि MrWiggles ने संकेत दिया है, ArrayList कंस्ट्रक्टर का उपयोग करना जो एक संग्रह लेता है, उदाहरण के लिए प्रदान किया गया तरीका है।

अधिक जटिल परिदृश्यों के लिए (जिसमें आपका वास्तविक कोड शामिल हो सकता है), आपको अमरूद के भीतर संग्रह मिल सकता है।


58

बस करो:

List a = new ArrayList(); 
a.add("a"); 
a.add("b"); 
a.add("c"); 
List b = new ArrayList(a);

ArrayList में एक कंस्ट्रक्टर है जो तत्वों को कॉपी करने के लिए एक और संग्रह स्वीकार करेगा


7
टिप्पणियों के नीचे किसी के रूप में, यह एक उथली प्रति है। अन्यथा यह एक अच्छा जवाब होता। मुझे लगता है कि मुझे निर्दिष्ट करना चाहिए था। कोई बात नहीं, मैं वैसे भी आगे बढ़ गया हूं।
जैस्पर फ्लोर

11
तार की सूची के लिए, गहरी प्रतिलिपि महत्वपूर्ण नहीं है क्योंकि Stringऑब्जेक्ट अपरिवर्तनीय हैं।
डेरेक महार

17

स्टीफन काटुलका (स्वीकृत उत्तर) का उत्तर गलत है (दूसरा भाग)। यह बताता है कि Collections.copy(b, a);एक गहरी प्रतिलिपि है, जो यह नहीं करता है। दोनों, new ArrayList(a);और Collections.copy(b, a);केवल एक उथली प्रतिलिपि करते हैं। अंतर यह है, कि कंस्ट्रक्टर नई मेमोरी आवंटित copy(...)करता है , और ऐसा नहीं करता है, जो इसे उन मामलों में उपयुक्त बनाता है जहां आप सरणियों का पुन: उपयोग कर सकते हैं, क्योंकि इसमें एक प्रदर्शन लाभ है।

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

के लिए स्रोत कोड Collections.copy(...)552 लाइन पर देखा जा सकता है: http://www.java2s.com/Open-Source/Java-Document/6.0-JDK-Core/Collections-Jar-Zip-Logging-regex/java/util/ Collections.java.htm

यदि आपको एक गहरी प्रतिलिपि की आवश्यकता है, तो आपको प्रत्येक ऑब्जेक्ट पर लूप और क्लोन () के लिए मैन्युअल रूप से आइटम पर पुनरावृत्त करना होगा।


12

सूची की प्रतिलिपि बनाने का सबसे सरल तरीका यह है कि इसे नई सूची के निर्माता के पास भेजा जाए:

List<String> b = new ArrayList<>(a);

b की उथली प्रति होगी a

के स्रोत को देखते हुए Collections.copy(List,List)(मैंने इसे पहले कभी नहीं देखा था) ऐसा लगता है कि यह इंडेक्स द्वारा तत्वों की नकल करने के लिए है। List.set(int,E)इस प्रकार एलिमेंट 0 का उपयोग टारगेट लिस्ट इत्यादि में एलिमेंट 0 से अधिक होगा। विशेष रूप से स्पष्ट नहीं है कि मुझे कबूल करना है।

List<String> a = new ArrayList<>(a);
a.add("foo");
b.add("bar");

List<String> b = new ArrayList<>(a); // shallow copy 'a'

// the following will all hold
assert a.get(0) == b.get(0);
assert a.get(1) == b.get(1);
assert a.equals(b);
assert a != b; // 'a' is not the same object as 'b'

आप 'उथली' कॉपी क्यों कहते हैं? - मुझे जावा
नोब

4
By उथली प्रतिलिपि ’से उनका तात्पर्य है कि प्रतिलिपि के बाद b में वस्तुएँ समान वस्तुएं हैं जैसे कि उनमें से प्रतियां नहीं हैं।
डीजेकेवर्थ

1
कलेक्शंस.कॉपी के लिए javadoc () कहता है "गंतव्य सूची कम से कम तब तक होनी चाहिए जब तक स्रोत सूची में है।"
डीजेकेवर्थ

मुझे लगता है कि मेरा मतलब यह है कि मुझे यह देखने के लिए कुछ पसंद आया कि समारोह वास्तव में क्या किया है और मैं देख सकता हूँ कि प्रश्नकर्ता को थोड़ा उलझन में है कि यह वास्तव में क्या करता है
गैरेथ डेविस

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

9
List b = new ArrayList(a.size())

आकार निर्धारित नहीं करता है। यह प्रारंभिक क्षमता निर्धारित करता है (आकार बदलने से पहले इसे कितने तत्वों में फिट किया जा सकता है)। इस मामले में नकल करने का एक सरल तरीका है:

List b = new ArrayList(a);

8

जैसा कि होइजई उल्लेख करते हैं। स्टीफन कटुल्का के चयनित उत्तर में कलेक्शन.कॉपी के बारे में एक टिप्पणी है जो गलत है। लेखक ने शायद इसे स्वीकार कर लिया क्योंकि कोड की पहली पंक्ति वह प्रतिलिपि थी जो वह चाहता था। Collections.copy के लिए अतिरिक्त कॉल फिर से कॉपी करता है। (दो बार हो रही कॉपी में रिजल्ट)।

यहाँ यह साबित करने के लिए कोड है।

public static void main(String[] args) {

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

    System.out.println("There should be no output after this line.");

    // Note, b is already a shallow copy of a;
    for (int i = 0; i < a.size(); i++) {
        if (a.get(i) != b.get(i)) {
            System.out.println("Oops, this was a deep copy."); // Note this is never called.
        }
    }

    // Now use Collections.copy and note that b is still just a shallow copy of a
    Collections.copy(b, a);
    for (int i = 0; i < a.size(); i++) {
        if (a.get(i) != b.get(i)) {
            System.out.println("Oops, i was wrong this was a deep copy"); // Note this is never called.
        }
    }

    // Now do a deep copy - requires you to explicitly copy each element
    for (int i = 0; i < a.size(); i++) {
        b.set(i, new String(a.get(i)));
    }

    // Now see that the elements are different in each 
    for (int i = 0; i < a.size(); i++) {
        if (a.get(i) == b.get(i)) {
            System.out.println("oops, i was wrong, a shallow copy was done."); // note this is never called.
        }
    }
}

5

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


5

आप न केवल addAllविधि का उपयोग क्यों करते हैं :

    List a = new ArrayList();
         a.add("1");
         a.add("abc");

    List b = b.addAll(listA);

//b will be 1, abc

यहां तक ​​कि अगर आपके पास बी में मौजूदा आइटम हैं या आप इसके बाद कुछ तत्वों को लटकाना चाहते हैं, जैसे:

List a = new ArrayList();
     a.add("1");
     a.add("abc");

List b = new ArrayList();
     b.add("x");
     b.addAll(listA);
     b.add("Y");

//b will be x, 1, abc, Y

3

यदि आप एक ArrayList को कॉपी करना चाहते हैं, तो इसका उपयोग करके कॉपी करें:

List b = new ArrayList();
b.add("aa");
b.add("bb");

List a = new ArrayList(b);

3

स्ट्रिंग्स के साथ गहरी नकल की जा सकती है

List<String> b = new ArrayList<String>(a);

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


8
यह अभी भी एक उथली प्रतिलिपि है क्योंकि सरणी का प्रत्येक तत्व bउसी अनुरूप Stringवस्तु को इंगित करता है a। हालाँकि, यह महत्वपूर्ण नहीं है क्योंकि, जैसा कि आप बताते हैं, Stringवस्तुएँ अपरिवर्तनीय हैं।
डेरेक महार

3
private List<Item> cloneItemList(final List<Item> items)
    {
        Item[] itemArray = new Item[items.size()];
        itemArray = items.toArray(itemArray);
        return Arrays.asList(itemArray);
    }

4
कृपया अपने उत्तर में कुछ स्पष्टीकरण जोड़ें
सम्पदा

1
इस कोड को इस सवाल का जवाब कर सकते हैं, के बारे में अतिरिक्त संदर्भ प्रदान करने के लिए कैसे और / या क्यों यह हल करती है समस्या जवाब की दीर्घकालिक मूल्य में सुधार होगा।
माइकल पार्कर

1

हर दूसरी वस्तु नहीं -> आपको इसे पुन: व्यवस्थित करने और स्वयं की प्रतिलिपि बनाने की आवश्यकता है।

इससे बचने के लिए क्लोन करने योग्य लागू करें।

public class User implements Serializable, Cloneable {

    private static final long serialVersionUID = 1L;

    private String user;
    private String password;
    ...

    @Override
    public Object clone() {
        Object o = null;
        try {
          o = super.clone();
        } catch(CloneNotSupportedException e) {
        }
        return o;
     }
 }

....

  public static void main(String[] args) {

      List<User> userList1 = new ArrayList<User>();

      User user1 = new User();
      user1.setUser("User1");
      user1.setPassword("pass1");
      ...

      User user2 = new User();
      user2.setUser("User2");
      user2.setPassword("pass2");
      ...

      userList1 .add(user1);
      userList1 .add(user2);

      List<User> userList2 = new ArrayList<User>();


      for(User u: userList1){
          u.add((User)u.clone());
      }

      //With this you can avoid 
      /*
        for(User u: userList1){
            User tmp = new User();
            tmp.setUser(u.getUser);
            tmp.setPassword(u.getPassword);
            ...
            u.add(tmp);               
        }
       */

  }

2
यह नहीं होना चाहिए "userList2.add ((उपयोगकर्ता) u.clone ());" ?
कृष्णप्रभाकर

1

निम्न आउटपुट कॉपी कंस्ट्रक्टर और कलेक्शंस.कोपी () का उपयोग करने के परिणामों को दिखाता है:

Copy [1, 2, 3] to [1, 2, 3] using copy constructor.

Copy [1, 2, 3] to (smaller) [4, 5]
java.lang.IndexOutOfBoundsException: Source does not fit in dest
        at java.util.Collections.copy(Collections.java:556)
        at com.farenda.java.CollectionsCopy.copySourceToSmallerDest(CollectionsCopy.java:36)
        at com.farenda.java.CollectionsCopy.main(CollectionsCopy.java:14)

Copy [1, 2] to (same size) [3, 4]
source: [1, 2]
destination: [1, 2]

Copy [1, 2] to (bigger) [3, 4, 5]
source: [1, 2]
destination: [1, 2, 5]

Copy [1, 2] to (unmodifiable) [4, 5]
java.lang.UnsupportedOperationException
        at java.util.Collections$UnmodifiableList.set(Collections.java:1311)
        at java.util.Collections.copy(Collections.java:561)
        at com.farenda.java.CollectionsCopy.copyToUnmodifiableDest(CollectionsCopy.java:68)
        at com.farenda.java.CollectionsCopy.main(CollectionsCopy.java:20)

पूर्ण कार्यक्रम का स्रोत यहां है: जावा सूची की प्रतिलिपि । लेकिन आउटपुट यह देखने के लिए पर्याप्त है कि java.util.Collections.copy () कैसे व्यवहार करता है।


1

और अगर आप Google अमरूद का उपयोग कर रहे हैं, तो एक लाइन समाधान होगा

List<String> b = Lists.newArrayList(a);

यह एक परिवर्तनशील सरणी सूची उदाहरण बनाता है।


1

Java 8 शून्य-सुरक्षित होने के कारण, आप निम्न कोड का उपयोग कर सकते हैं।

List<String> b = Optional.ofNullable(a)
                         .map(list -> (List<String>) new ArrayList<>(list))
                         .orElseGet(Collections::emptyList);

या एक कलेक्टर का उपयोग कर

List<String> b = Optional.ofNullable(a)
                         .map(List::stream)
                         .orElseGet(Stream::empty)
                         .collect(Collectors.toList())

0

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

एक उदाहरण: a = [1,2,3,4,5] b = [2,2,2,3,3,3,3,3,4,4,4,] a.copy (b) = [1,2,3,4,5,3,3,3,3,4,4,4]

हालांकि मुझे एक कॉपी विधि की उम्मीद होगी जो स्रोत और लक्ष्य संग्रह के प्रारंभ सूचकांक के लिए अतिरिक्त पैरामीटर लेगी, साथ ही गणना के लिए एक पैरामीटर।

जावा बीयूजी 6350752 देखें


-1

यह समझने के लिए कि Collections.copy () एक IndexOutOfBoundsException को क्यों फेंकता है, हालांकि आपने गंतव्य सूची का बैकिंग एरे को काफी बड़ा कर दिया है (सोर्सलिस्ट पर आकार () कॉल के माध्यम से), इस संबंधित प्रश्न में अभय यादव द्वारा उत्तर देखें: कैसे एक java.util की नकल करें। दूसरे java.util की सूची दें

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