2010-04-25 19 views
26

ठीक है, मैंने कई स्थानों और स्रोतों से सुना है कि जब भी मैं बराबर() विधि को ओवरराइड करता हूं, तो मुझे हैशकोड() विधि को ओवरराइड करने की आवश्यकता होती है। लेकिन कोडजब मैं बराबर() विधि को ओवरराइड करता हूं तो मुझे हैशकोड() को ओवरराइड क्यों करना चाहिए?

package test; 

public class MyCustomObject { 

    int intVal1; 
    int intVal2; 

    public MyCustomObject(int val1, int val2){ 
     intVal1 = val1; 
     intVal2 = val2; 
    } 

    public boolean equals(Object obj){ 
     return (((MyCustomObject)obj).intVal1 == this.intVal1) && 
       (((MyCustomObject)obj).intVal2 == this.intVal2); 
    } 

    public static void main(String a[]){ 
     MyCustomObject m1 = new MyCustomObject(3,5); 
     MyCustomObject m2 = new MyCustomObject(3,5); 
     MyCustomObject m3 = new MyCustomObject(4,5); 

     System.out.println(m1.equals(m2)); 
     System.out.println(m1.equals(m3)); 
    } 
} 

यहाँ का निम्न भाग पर विचार उत्पादन होता है सच है, झूठी ठीक वैसी ही मैं इसे होना चाहता हूँ और मैं बिल्कुल hashCode() विधि अधिभावी का ख्याल नहीं है। इसका मतलब है कि हैशकोड() ओवरराइडिंग एक विकल्प है जो हर किसी के जैसा अनिवार्य है।

मुझे एक दूसरी पुष्टि चाहिए।

+0

http://stackoverflow.com/questions/371328/why-is-it-important-to-override-gethashcode-when-equals-method-is-overriden-in-c – Oded

+4

का डुप्लिकेट नहीं वो वाला; वह सी # है, यह जावा है। (यह मुद्दा बहुत समान है, शायद समान है, लेकिन फिर भी।) – Thomas

उत्तर

32

यह आपके लिए काम करता है क्योंकि आपका कोड किसी भी कार्यक्षमता (हैश मैप, हैशटेबल) का उपयोग नहीं करता है, जिसके लिए hashCode() API की आवश्यकता होती है।

हालांकि, आपको नहीं पता कि आपकी कक्षा (संभवतः एक-ऑफ के रूप में नहीं लिखी गई) को बाद में एक कोड में बुलाया जाएगा जो वास्तव में हैश कुंजी के रूप में अपनी वस्तुओं का उपयोग करता है, इस मामले में चीजें प्रभावित होंगी।

प्रति documentation for Object class के रूप में:

hashCode के सामान्य अनुबंध है:

  • जब भी यह एक जावा अनुप्रयोग के निष्पादन के दौरान एक ही वस्तु एक बार से अधिक पर शुरू हो जाती है, hashCode विधि को लगातार एक ही पूर्णांक को वापस करना होगा, बशर्ते ऑब्जेक्ट पर तुलना के बराबर उपयोग की जाने वाली कोई भी जानकारी संशोधित न हो। इस पूर्णांक को एक आवेदन के निष्पादन से एक ही आवेदन के दूसरे निष्पादन के अनुरूप नहीं होना चाहिए।

  • दो तो वस्तुओं बराबर (वस्तु) विधि के अनुसार बराबर हैं, तो दो वस्तुओं में से प्रत्येक पर hashCode विधि एक ही पूर्णांक परिणाम का उत्पादन होगा बुला।

+1

और वैकल्पिक रूप से, 'हैशकोड' को सर्वोत्तम प्रदर्शन करना होगा ताकि कार्यक्रम के समान निष्पादन के दौरान कई मूल्यों पर एक ही पूर्णांक को वापस न किया जा सके। मेरे पास एक बार प्रदर्शन बग था कि मुझे डिफ़ॉल्ट (संरचनात्मक) हैश फ़ंक्शन के साथ भौतिक समानता का उपयोग करने के लिए एक लंबा समय लगा। यह उपयोग उपर्युक्त शर्तों को पूरा करता है, लेकिन सभी संरचनात्मक रूप से समान, शारीरिक रूप से अलग-अलग मूल्य एक ही बाल्टी को धोए गए थे। –

+0

@ पास्कल - यह सही है। वास्तव में दस्तावेज़ जारी है: * यह आवश्यक नहीं है कि यदि दो वस्तुएं बराबर (java.lang.Object) विधि के अनुसार असमान हैं, तो दो वस्तुओं में से प्रत्येक पर हैशकोड विधि को कॉल करना अलग पूर्णांक परिणाम उत्पन्न करना चाहिए। ** हालांकि, प्रोग्रामर को पता होना चाहिए कि असमान वस्तुओं के लिए अलग पूर्णांक परिणाम उत्पन्न करने से हैशटेबल्स ** के प्रदर्शन में सुधार हो सकता है। – DVK

+0

"... जितना व्यावहारिक रूप से व्यावहारिक है, वर्ग ऑब्जेक्ट द्वारा परिभाषित हैशकोड विधि अलग-अलग वस्तुओं के लिए अलग-अलग पूर्णांक लौटाती है। (यह आमतौर पर ऑब्जेक्ट के आंतरिक पते को पूर्णांक में परिवर्तित करके कार्यान्वित किया जाता है, लेकिन यह कार्यान्वयन तकनीक नहीं है जावा प्रोग्रामिंग भाषा द्वारा आवश्यक है।) " – DVK

10

क्योंकि हैश मैप/हैशटेबल पहले हैशकोड() द्वारा ऑब्जेक्ट लुकअप करेगा।

यदि वे समान नहीं हैं, तो हैशपैप जोर देगी कि वस्तु समान नहीं है और मानचित्र में वापसी मौजूद नहीं है।

5

कारण आपको @Override की आवश्यकता क्यों नहीं है, दोनों या तो दोनों एपीआई के साथ पारस्परिक संबंध के कारण हैं।

आप पाएंगे कि यदि आप m1 को HashSet<MyCustomObject> में डालते हैं, तो यह contains(m2) नहीं है। यह असंगत व्यवहार है और बहुत सारी बग और अराजकता पैदा कर सकता है।

जावा लाइब्रेरी में कई कार्यक्षमताएं हैं। उन्हें के लिए काम करने के लिए, आपको नियमों से खेलना होगा, और यह सुनिश्चित करना होगा कि equals और hashCode संगत हैं, सबसे महत्वपूर्ण हैं।

4

अन्य टिप्पणी में से अधिकांश पहले से ही आप जवाब दिया: एक अनुकूलन के रूप में hashCode का उपयोग करता है करने के लिए "सूचकांक" वस्तु उदाहरणों, एक: यदि आप यह करने के लिए, क्योंकि वहाँ संग्रह (HashSet, HashMap यानी) कर रहे हैं की जरूरत है उन अनुकूलन से उम्मीद है कि यदि: a.equals(b) ==>a.hashCode() == b.hashCode() (ध्यान दें कि उलटा नहीं है)।

लेकिन एक अतिरिक्त जानकारी के रूप में आप इस अभ्यास कर सकते हैं:

class Box { 
    private String value; 
    /* some boring setters and getters for value */ 
    public int hashCode() { return value.hashCode(); } 
    public boolean equals(Object obj) { 
      if (obj != null && getClass().equals(obj.getClass()) { 
       return ((Box) obj).value.equals(value); 
      } else { return false; } 
    } 
} 

ऐसा करते हैं:

Set<Box> s = new HashSet<Box>(); 
Box b = new Box(); 
b.setValue("hello"); 
s.add(b); 
s.contains(b); // TRUE 
b.setValue("other"); 
s.contains(b); // FALSE 
s.iterator().next() == b // TRUE!!! b is in s but contains(b) returns false 

क्या आप इस उदाहरण से पता चलता है कि equals या hashCode को लागू करने प्रॉपर्टी के साथ किया जा सकता है बदला (mutable) वास्तव में एक बुरा विचार है।

0

संग्रह में अपने हैशकोड() मान का उपयोग करके ऑब्जेक्ट की खोज करते समय यह मुख्य रूप से महत्वपूर्ण है (यानी हैश मैप, हैशसेट, आदि)। प्रत्येक ऑब्जेक्ट एक अलग हैशकोड() मान देता है इसलिए संग्रह के एल्गोरिदम को हैश तालिका पर मानों का पता लगाने में मदद करने के लिए ऑब्जेक्ट की स्थिति के आधार पर हैशकोड मान को लगातार उत्पन्न करने के लिए आपको इस विधि को ओवरराइड करना होगा।

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