2012-04-02 9 views
5

कुछ प्रमुख JVM वर्गों (जैसे String या List implementations) को लागू हर field_n कि equals विधि के लिए प्रासंगिक है के लिए Σ 31^n * field_n.hashCode() वापस लौट कर बराबर होती है। इसके अलावा, प्रभावशाली जावा (आइटम 9) में जोशुआ ब्लोच द्वारा इस दृष्टिकोण की सिफारिश की जाती है।hashCode कार्यान्वयन रणनीतियों

हालांकि, Map.Entry implementations जैसे अन्य वर्ग विभिन्न नियमों का पालन करते हैं। उदाहरण के लिए, Map.Entry प्रलेखन कहा गया है कि एक Map.Entry के हैश कोड होना चाहिए

(e.getKey()==null ? 0 : e.getKey().hashCode())^
(e.getValue()==null ? 0 : e.getValue().hashCode()) 

यह कभी कभी हैश तालिकाओं में उपयोग करने के लिए अव्यावहारिक हो सकता है, के बाद से:

  • सभी प्रविष्टियों का हैश कोड जिसमें एक ही कुंजी और मान 0 है,
  • दो प्रविष्टियां ई 1 और ई 2 ताकि e1.key = e2.value और e1.value = e2.key के पास एक ही हैश कोड हो।

क्यों जावा उदाहरण, 31 * (e.getKey()==null ? 0 : e.getKey().hashCode()) + (e.getValue()==null ? 0 : e.getValue().hashCode()) के लिए, के बजाय Map.Entry hashCode के लिए इस कार्यान्वयन विनिर्देश चुना?

संपादित करें 1:

समस्या यह पता लगाने में मदद करने के लिए, यहाँ है, जहाँ परिणाम हैश टकराव के कारण बहुत खराब प्रदर्शन है, तो कई प्रविष्टियों एक ही कुंजी और मान होना उपयोगी कोड का एक उदाहरण है।

यह विधि विभिन्न मानचित्रों की प्रविष्टियों की आवृत्तियों की गणना करती है (गुवा के मल्टीसेट का उपयोग करके)।

public static <K, V> Multiset<Map.Entry<K, V>> computeEntryCounts(
     Iterable<Map<K, V>> maps) { 
    ImmutableMultiset.Builder<Map.Entry<K, V>> result = ImmutableMultiset.builder(); 
    for (Map<K, V> map : maps) { 
     for (Map.Entry<K, V> entry : map.entrySet()) { 
      result.add(entry); 
     } 
    } 
    return result.build(); 
} 
+0

आपका कार्यान्वयन कुंजी और मूल्य ** शून्य ** के आउटपुट को प्रभावित नहीं करता है। इसके अलावा, जावा में एक मानचित्र में एक कुंजी के साथ ** एक ** प्रविष्टि नहीं है, किसी भी मानचित्र कार्यान्वयन में केवल एक बार ** ** होता है। –

+0

मुझे पता है, मैं मान रहा था कि हैश मैप की चाबियाँ मैप के उदाहरण हैं। एंटर्री। ऐसा तब हो सकता है जब आप कई मानचित्रों में प्रत्येक कुंजी-मूल्य प्रविष्टि के लिए कुल गणना की गणना करना चाहते हैं। – jpountz

+0

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

उत्तर

4

मुझे शक है इसका कोई खास कारण — मुझे लगता है कि यह सिर्फ एक निरीक्षण — है, लेकिन यह एक गंभीर समस्या नहीं है के लिए एक बेहतर फिटिंग एल्गोरिथ्म पता है। यह केवल तभी आएगा जब आपके पास HashSet<Map.Entry<T,T>> या HashMap<Map.Entry<T,T>,V> था, जो आमतौर पर नहीं किया जाता है। क्योंकि यह अपनी चाबी से प्रविष्टियों को खोजता है

ध्यान दें कि HashMap<K,V> करता नहीं उपयोग Map.Entry<K,V>.hashCode(),: (, के रूप में जोआचिम सौएर नीचे बताते हैं या, एक HashSet<Map<T,T>> या एक HashMap<Map<T,T>,V> — भी आमतौर पर ऐसा नहीं किया जोड़ने के लिए संपादित।) केवल, इसलिए यह K.hashCode() का उपयोग करता है।

+1

चूंकि 'Map.hashCode() 'को' Map.Entry' तत्वों के 'हैशकोड' के संदर्भ में परिभाषित किया गया है, यह भी 'मानचित्र , V2>' में आता है। या 'सेट > '। लेकिन उनसे आसानी से बचा जा सकता है (और आमतौर पर पठनीयता और डिजाइन के कारणों से भी बचा जाना चाहिए)। –

+0

@ जोचिमसौयर: अच्छा बिंदु, धन्यवाद! – ruakh

+0

इस समस्या में भाग लेने के लिए यह सब कुछ है 'someHashSet.addAll (someMap.entrySet())' या ऐसा कुछ [गुवा मुद्दा] (http://code.google.com/p/guava-libraries/issues/detail ? id = 458)। "ए" => "ए" जैसी सभी प्रविष्टियां टकराव की गारंटी देती हैं और प्रदर्शन को भयानक होने की गारंटी दी जाती है (या जेडीके 8 के बाद से कम से कम इष्टतम)। आप शायद ही कभी इसमें भाग लेते हैं, लेकिन जब आप ऐसा करते हैं तो यह बहुत बुरा होता है। – maaartinus

0

मेरा व्यक्तिगत अनुमान है, हैशकोड भी तेज़ होना चाहिए।

चूंकि आपको हैशकोड को ओवरराइड करने की अनुमति है, इसके साथ कोई समस्या नहीं है। यह बदलें, जब आप अपने मामले

+2

क्षमा करें, लेकिन यह सही नहीं है। 'Map.Entry' एक * इंटरफ़ेस * है। यह एक * डिफ़ॉल्ट * एल्गोरिदम का वर्णन नहीं कर रहा है कि * यह * लागू करता है लेकिन वह उप-वर्ग ओवरराइड कर सकते हैं; बल्कि, यह एक विशिष्ट एल्गोरिदम निर्धारित कर रहा है कि कार्यान्वयनकर्ताओं को लागू करने की आवश्यकता है। – ruakh

+0

जब सूर्य/ऑरैकल को सभी मामलों में एक निश्चित कार्यान्वयन की आवश्यकता होती है, तो उन्हें इंटरफेस के बजाय एक अमूर्त वर्ग का उपयोग करना चाहिए। –

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