2015-06-08 4 views
11

HashMap.values() के स्रोत कोड के रूप मेंHashMap.values ​​() और HashMap.keySet() मूल्य और कुंजी कैसे लौटते हैं?

public Collection<V> values() { 
    Collection<V> vs = values; 
    return (vs != null ? vs : (values = new Values())); 
} 

आप देख सकते हैं, जब values() विधि पहले कहा जाता है, यह सिर्फ एक Values ऑब्जेक्ट इस प्रकार दिखाया गया है। Values ऑब्जेक्ट AbstractCollection का कोई सबक्लूस नहीं है जिसमें कोई कन्स्ट्रक्टर नहीं है, और निश्चित रूप से कोई तत्व नहीं है। लेकिन जब मैंने विधि को बुलाया, तो उसने तेजी से संग्रह

Collection<String> values = map.values(); 
System.out.println(values); 

यह इतना अजीब है। न केवल values(), लेकिन keySet() और entrySet() विधि ऐसी खाली वस्तुओं को वापस लौटाती है। तो, मेरा प्रश्न यह है कि, इन विधियों को हमारे द्वारा आवश्यक तत्वों के साथ वस्तुओं को कब और कैसे किया जाता है?

उत्तर

20

यह एक गलत धारणा है कि Values कक्षा "निश्चित रूप से खाली है"। सिर्फ इसलिए कि इस पर कोई विधि नहीं है और इसके कन्स्ट्रक्टर के पास कोई तर्क नहीं है इसका मतलब यह नहीं है कि संग्रह खाली है।

Values वर्ग HashMap का एक "आंतरिक वर्ग" (एक गैर स्थिर nested class), जिसका अर्थ यह HashMap उद्देश्य यह है कि यह बनाया करने के लिए एक अंतर्निहित संदर्भ पड़ता है। इसलिए के सभी तत्वों को स्पष्ट रूप से HashMap.this संदर्भ या सीधे सदस्यों तक पहुंचकर उपयोग कर सकते हैं। चूंकि यह एक आंतरिक वर्ग है, इसलिए इसे HashMap के निजी सदस्यों तक पहुंचने की भी अनुमति है।

उदाहरण के लिए आप देख सकते हैं कि Values कक्षा में 'size विधि के क्रियान्वयन:

public int size() { 
    return size; 
} 

Values वर्ग एक size सदस्य नहीं है, तो यह है कि sizeHashMap को संदर्भित करता है के आकार।यह करने के लिए बराबर है:

public int size() { 
    return HashMap.this.size; 
} 

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

// Getting the entry set (not a copy!) 
    Set<Entry<String, String>> entries = map.entrySet(); 

    // Add elements to the map afterwards 
    map.put("abc", "def"); 

    // Check out the entries in the collection 
    // (magically containing the elements added after getting the collection) 
    System.out.println(entries); // "[abc=def]" 
+1

'ध्यान दें कि इसका अर्थ यह भी है कि आपके द्वारा प्राप्त संग्रह एक प्रति नहीं है, लेकिन फिर भी मूल हैश मैप सामग्री को संदर्भित करता है और इसलिए जब आप हैश मैप अपडेट करते हैं तो परिवर्तन होता है:' जिसे Map.values ​​के अनुबंध में स्पष्ट रूप से लिखा गया है)), किसी भी गलतफहमी से बचने के लिए। – biziclop

+0

एक आंतरिक वर्ग एक गैर स्थैतिक घोंसला वर्ग है, यानी वर्ग स्थिर था, यह एक आंतरिक वर्ग नहीं होगा, बल्कि बस एक स्थिर घोंसला वर्ग होगा। https://docs.oracle.com/javase/tutorial/java/javaOO/nested.html – Sardtok

+0

@ सार्डटोक: संकेत के लिए धन्यवाद, मैंने आधिकारिक शब्दावली का उपयोग करने के लिए अभी जवाब संपादित किया है। – mastov

13

Values कक्षा Collection लागू करती है जो HashMap द्वारा समर्थित है। जैसा कि मास्टोव ने टिप्पणी की, ValuesHashMap का एक आंतरिक वर्ग है, जो इसे HashMap उदाहरण के साथ जुड़े हुए उदाहरण के सदस्यों तक पहुंच प्रदान करता है। इसलिए यह खाली नहीं है। इसका आकार HashMap का आकार है, और जब आप इसे फिर से चालू करते हैं, तो आप HashMap की प्रविष्टियों पर पुनरावृत्त कर रहे हैं।

जब आप System.out.println(values); कहते हैं, आप जो एक Iterator का उपयोग करता मूल्यों पर पुनरावृति और उनके String प्रतिनिधित्व प्राप्त करने के लिए AbstractCollection की toString विधि, बुला रहे हैं। Iterator वास्तव में HashMap की प्रविष्टियों पर फिर से शुरू होता है और उनके मान देता है।

Set एस keySet और entrySet द्वारा लौटाया गया है।

+0

शायद आपको यह उल्लेख करना चाहिए कि 'मानों' वर्ग एक गैर स्थैतिक आंतरिक वर्ग है, इसलिए बाहरी वर्ग 'हैश मैप' के लिए यह सूचक 'निहित' है। इस तरह यह मानचित्र के तत्वों का संदर्भ दे सकता है, भले ही उसके कन्स्ट्रक्टर को कोई तर्क न हो। – mastov

+0

@mastov अच्छा बिंदु – Eran

+0

धन्यवाद @Eran और @mastov। मुझे पता है कि जब हम 'मान' को पुन: सक्रिय करते हैं तो इटेटरेटर विधि अच्छी तरह से काम कर सकती है। हालांकि, जब मैंने 'संग्रह मान = map.values ​​();' लाइन पर एक ब्रेकपॉइंट सेट किया है, 'लाइन और प्रोग्राम डीबग करें, तो पहले से ही System.out.println (मानों) को कॉल करने से पहले मानों को संग्रह के रूप में सेट कर दिया गया है, और यहां कोई पुनरावृत्ति नहीं है। यह वह बिंदु है जहां मैं अजीब महसूस करता हूं। – Yohn

2
Collection<V> vs = values; 
return (vs != null ? vs : (values = new Values())); 

ये दो पंक्ति आपके प्रश्न का उत्तर देती हैं।

values एक आंतरिक संग्रह है (AbstractMap से विरासत)। यदि यह null नहीं है तो यह वापस कर दिया जाएगा।
यदि यह null है तो इसे आरंभ किया जाएगा और नया एक वापस आ जाएगा।

अब मुझे लगता है कि आपके प्रश्न का मुख्य बिंदु
इन तरीकों से हमें आवश्यक तत्वों के साथ ऑब्जेक्ट्स कैसे लौटाते हैं?

तकनीकी रूप से values हमेशा इस प्रारंभिक ऑब्जेक्ट को वापस करें। फिर हम इन ऑब्जेक्ट से हमारे प्रवेश मूल्य कैसे प्राप्त करते हैं।

मूल्यों() वास्तव में वर्ग Values की एक वस्तु जो HashMap के इनर वर्ग है और फैली AbstractCollection

private final class Values extends AbstractCollection<V> 

आप स्रोत कोड में देखा है के रूप में वापसी:
जाना थोड़ा गहरा करने देता है। तो फिर तुम Values वर्ग

public Iterator<V> iterator() { 
     return newValueIterator(); 
    } 

इस newValueIterator() काम कर देता है अंदर मिल जाएगा।
आप और अधिक जाते हैं गहरी आप ValueIterator की newValueIterator() रिटर्न वस्तु जो HashIterator HashIterator का एक उपवर्ग है यात्रा के लिए बुनियादी कार्यक्षमता है, जो वास्तव itterate table से अधिक HashMap द्वारा बनाए रखा लागू करता मिल जाएगा।

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