2013-08-21 5 views
15

वहां पर बहुत भ्रम और अलग-अलग राय दिखाई देती हैं ([1] और अन्य स्रोत) Arrays.copyOf पर गहरी या उथली प्रतिलिपि उत्पन्न होगी।क्या Arrays.copyOf उथले या गहरी प्रतिलिपि बनाता है?

यह परीक्षण पता चलता है कि प्रति गहरा है:

String[] sourceArray = new String[] { "Foo" }; 
String[] targetArray = java.util.Arrays.copyOf(sourceArray, 1); 

sourceArray[0] = "Bar"; 

assertThat(targetArray[0]).isEqualTo("Foo"); // passes 

यह परीक्षण पता चलता है कि प्रति उथला है:

String[][] sourceArray = new String[][] { new String[] { "Foo" } }; 
String[][] targetArray = java.util.Arrays.copyOf(sourceArray, 1); 

sourceArray[0][0] = "Bar"; 

assertThat(targetArray[0][0]).isEqualTo("Foo"); // fails 

समाधान है बस उस शीर्ष स्तर के आयाम की एक गहरी प्रतिलिपि बनाया गया है, लेकिन अन्य आयाम एक उथली प्रतिलिपि हैं? सच क्या है?

[1] How do I do a deep copy of a 2d array in Java?

+0

शायद सिर्फ स्ट्रिंग्स – Matthias

+0

@Matthias का होना शामिल की एक और घटना। चूंकि "फू" एक शाब्दिक है, इसलिए इसे प्रशिक्षित किया जाएगा; परीक्षण मानते हैं कि। यदि वह धारणा सही है, तो परीक्षण जांच कर रहे हैं कि लक्षित तत्व को स्रोत स्रोत तत्व के '=" बार "द्वारा बदला गया है या नहीं। – ToolmakerSteve

+0

मुझे नहीं पता कि परीक्षण कहां से अंतर्निहित हैं कि स्ट्रिंग्स आंतरिक हैं या नहीं।मुझे कोई पहचान परीक्षण नहीं दिख रहा है, मुझे केवल समानता परीक्षण दिखाई देता है। परिणाम उथले और गहरी प्रतियों के लिए समान होंगे, क्योंकि समानता परीक्षण उथले और गहरी प्रतियों के बीच भिन्न नहीं हो सकते हैं। उथले और गहरी प्रतियों के बीच अंतर करने के लिए किसी को पहचान परीक्षण की आवश्यकता होती है। –

उत्तर

22

यह एक उथले प्रतिलिपि है, यानी एक नई सरणी कि "पुराने" संदर्भ शामिल हैं पैदा करता है (एक ही वस्तुओं के लिए, उन प्रतिलिपि बनाई जा रही नहीं कर रहे हैं)।

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

यह परीक्षण पता चलता है कि प्रति गहरा है:

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

String x = "foo"; 
String y = x; 
x = "bar"; 

assertEquals(y, "foo"); 

नहीं "गहरी प्रतिलिपि" यहाँ:

यह रूप में एक ही स्थिति है।

4

फार्म Java Doc

.... दो सरणियों समान मूल्यों शामिल होंगे।

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

-4

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

सार्वजनिक वर्ग ArrayTest {

public static void main(String [] args) { 
    Object [] objs = new Object[1]; 
    objs[0] = new Object(); 
    System.out.println("Original: " + objs[0].toString()); 

    Object [] copy = java.util.Arrays.copyOf(objs, 1); 
    objs[0] = new Object(); 
    System.out.println("copy, after original reassigned: " + 
    copy[0].toString()); 
    System.out.println("Original, after reassigned: " + 
    objs[0].toString()); 
} 

}

+1

यह एक गहरी प्रति नहीं है, एक गहरी प्रतिलिपि स्वयं सरणी में संग्रहीत सभी वस्तुओं की प्रतियां बनाने में सक्षम होगी। Arrays.copyOf ऐसा नहीं करता है; यह केवल संदर्भों की प्रतियां बनाता है - यानी एक उथली प्रतिलिपि –

+0

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

+0

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

1

'उथला' या 'गहरी' - और यह एक बात है कि मैं कोई भी ठीक परिभाषित करने को देखने के है - विधि Arrays.copyOf(..) व्यवहार में करता है एक प्रति का उत्पादन स्रोत सरणी का जो स्रोत सरणी में परिवर्तनों से अप्रभावित रहता है।

पूर्णांक सरणियों के साथ निम्नलिखित सरल उदाहरण लें:

import java.util.Arrays; 

public class DeepCopyTest 
{ 

    public static void main(String[] args) 
    { 
     int[] source = { 1, 2, 3, 4, 5, 6}; 
     int[] target = new int[source.length]; 
     // Copy target from source via Arrays.copyOf(..) method : 
     target = Arrays.copyOf(source, 6); 
     // Check for equality : 
     System.out.println("Source1 : " + Arrays.toString(source)); 
     System.out.println("Target1 : " + Arrays.toString(target)); 
     // Increment all entries in source array : 
     for(int i = 0; i < source.length; i++) 
     { 
      source[i] = source[i] +1; 
     } 
     // See if target is affected : 
     System.out.println("Source2 : " + Arrays.toString(source)); 
     System.out.println("Target2 : " + Arrays.toString(target)); 

    } 

} 

// OUTPUT 
// ------ 
Source1 : [1, 2, 3, 4, 5, 6] 
Target1 : [1, 2, 3, 4, 5, 6] 
Source2 : [2, 3, 4, 5, 6, 7] 
Target2 : [1, 2, 3, 4, 5, 6] 

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

और यह Arrays.copyOf (..) 'विधि उन्हें यह देती है।

साथ ही आदिम प्रकार सरणियों, स्ट्रिंग ऑब्जेक्ट सरणियों भी ऊपर के उदाहरण के रूप में व्यवहार करते हैं, जैसे उत्पादन दे रही है:

Source1 : [a, b, c, d, e, f] 
Target1 : [a, b, c, d, e, f] 
Source2 : [a1, b1, c1, d1, e1, f1] 
Target2 : [a, b, c, d, e, f] 

जब प्रारंभिक स्रोत सरणी प्रविष्टियों "1" से concatenated रहे हैं।

यह ऑब्जेक्ट एरे के लिए भी 'काम करता है' इस अर्थ में कि लक्ष्य को फिर से सौंपे जाने पर स्रोत से अब बंधे नहीं हैं। लेकिन नकल के बाद दोनों सरणियों के पहले तत्व के लिए और उसके बाद स्रोत में फेरबदल के बाद उत्पादन को देख [0] पूरा सच का पता चलता है:

Source1 : [email protected] 
Target1 : [email protected] 
Source2 : [email protected] 
Target2 : [email protected] 

के बाद मूल स्रोत सरणी नकल की जाती है लक्ष्य तत्वों बस ओर इशारा किया गया है वर्तमान में उनके स्रोत समकक्षों में जो भी मूल्य रखे जाते हैं। लक्ष्य के लिए [0] यह स्मृति पता 1 डीबी 9 742 की सामग्री है - जो एक ही मेमोरी एड्रेस होल्डिंग स्रोत [0] है। । । ।

और कारण है कि हम स्रोत [0] को पुन: असाइन करने के बाद स्रोत और लक्ष्य के बीच एक debonding मिल तथ्य यह है कि काम के बयान

source[0] = new Object(); 

बस स्मृति संदर्भ स्रोत में आयोजित का कारण बनता है की वजह से है [0] को किसी नए ऑब्जेक्ट को इंगित करने के रूप में कुछ नए स्थान पर बदला जा सकता है। तो यह शुद्ध अर्थ में एक सच्ची गहरी प्रतिलिपि के बाद नहीं है, भले ही कई मामलों में यह कोडर को गहरी प्रति के समान लाभ प्रदान करता है।

आदिम डेटा के सरणी के साथ Arrays.copyOf (..) विधि संदर्भों की प्रतिलिपि नहीं बना सकती क्योंकि इन्हें प्राइमेटिव के लिए उपयोग नहीं किया जाता है। यह केवल स्रोत तत्व मानों को लक्षित तत्वों में प्रतिलिपि बनाता है। फिर से हमारे पास एक गहरी प्रतिलिपि के मुकाबले बहुत कम कोड की आवश्यकता वाले ऑपरेशन की कीमत पर गहरी प्रतिलिपि के समान प्रभाव पड़ता है।

तो Arrays.copyOf (..) आदिम और 1-डी ऑब्जेक्ट एरे दोनों के लिए एक 'सस्ता' गहरी प्रति है। लेकिन कोई डेटा सरणी अधिक जटिल है और यह पता चला है।

शायद इसे अर्ध-गहरी प्रतिलिपि कहा जाना चाहिए।

0

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

import java.util.*; 
import java.lang.*; 
import java.io.*; 

/* Name of the class has to be "Main" only if the class is public. */ 
class ArraysCopyOfDemo 
{ 
    public static void main (String[] args) throws java.lang.Exception 
    { 
     Object[] originalArray= new Object[1]; 
     Employee e1= new Employee("Salman","Khan"); 
     originalArray[0]=e1; 
     System.out.println("Original Array content printed "); 
     printArray(originalArray); 

     Object[] copiedArray=originalArray.clone(); 
     System.out.println("Copied Array content printed "); 
     printArray(copiedArray); 
     System.out.println("Copied Array content modified "); 
     Employee CopiedEmp1= (Employee)copiedArray[0]; 
     CopiedEmp1.setFirstname("Amir"); 
     System.out.println("Copied Array content printed "); 
     printArray(copiedArray); 
     System.out.println("Original Array content printed to verify shallow copy or deep copy"); 
     printArray(originalArray); 
    } 
    private static void printArray(Object[] arrays){ 
     for(Object emp:arrays){ 
      System.out.print(((Employee)emp).getFirstname() + " "); 
      System.out.print(((Employee)emp).getLastname()); 
      System.out.println(); 
     } 
    } 
} 
class Employee implements Cloneable{ 
    private String firstname; 
    private String lastname; 
    public Employee(String firstname,String lastname){ 
     this.firstname=firstname; 
     this.lastname=lastname; 
    } 
    public String getFirstname(){ 
     return firstname; 
    } 
    public String getLastname(){ 
     return lastname; 
    } 
    public void setFirstname(String firstname){ 
     this.firstname=firstname; 
    } 
    public void setLirstname(String lastname){ 
     this.lastname=lastname; 
    } 

} 

O/p 
Original Array content printed 
Salman Khan 
Copied Array content printed 
Salman Khan 
Copied Array content modified 
Copied Array content printed 
Amir Khan 
Original Array content printed to verify shallow copy or deep copy 
Amir Khan 
संबंधित मुद्दे