2009-07-09 21 views
14

मैं हैश मैप में एक कुंजी का पता लगाने की कोशिश कर रहा हूं। मैं 'प्राप्त' का उपयोग करके चयनित कुंजी मुद्रित कर सकता हूं लेकिन जब मैं किसी कथन में 'includeKey' का उपयोग करता हूं, तो यह नहीं मिलता है।जावा हैशैप काम करता है लेकिन इसमें शामिल है

मुझे पता है कि कुंजी मानचित्र में मौजूद है लेकिन यह झूठी वापसी करता रहता है। कोई विचार लोग?

मेरे कोड:

public class Location { 

    protected int _x; 
    protected int _y; 
    protected int _z; 

    public Location(int xAxis, int yAxis, int zAxis) { 
     this._x = xAxis; 
     this._y = yAxis; 
     this._z = zAxis; 
    } 

    public void equals() { 
     //not implemented yet 
    } 

    public void HashCode() { 
     //not implemented yet 
    } 

    public String toString() { 
     String locationString = Integer.toString(_x) + Integer.toString(_y) + Integer.toString(_z); 
     return locationString; 
    } 

    public void setX(int XAxis) { 
     this._x = XAxis; 
    } 

    public int getX() { 
     return this._x; 
    } 

    public void setY(int YAxis) { 
     this._y = YAxis; 
    } 

    public int getY() { 
     return this._y; 
    } 

    public void setZ(int ZAxis) { 
     this._z = ZAxis; 
    } 

    public int getZ() { 
     return this._z; 
    } 

} 
+0

क्या यह सही कोड है जिसे आप चल रहे हैं? यदि नहीं, तो आप जिस सटीक कोड का उपयोग कर रहे हैं उसे प्रदान करें (मैं केवल इसलिए पूछता हूं क्योंकि किसी अन्य प्रश्न में, जो आपने प्रदान किया वह आपकी समस्या का प्रतिनिधि नहीं था, और बहुत भ्रम पैदा हुआ)। –

+0

इसके अलावा, यह व्यवहार लगातार है? यानी, प्राप्त करें (...) * हमेशा * अपेक्षित होने पर कुछ लौटाता है, और इसमें शामिल है (...) * कभी नहीं * करता है? –

+0

क्या आप जेडीके के साथ विकास कर रहे हैं जिसमें स्रोत कोड शामिल है? यदि ऐसा है, तो शायद आपको कोड को डीबग करने और हैश मैप विधियों में शामिल होना चाहिए (इसमें शामिल है और प्राप्त करें) यह देखने के लिए कि क्या आप कोई असामान्य व्यवहार कर सकते हैं या नहीं। चिंता न करें, ये विधियां बहुत जटिल हैं। –

उत्तर

23

आपको सुनिश्चित करना होगा कि Location वर्ग ठीक से अपनी hashCode() और equals(Object) विधियों (documentation) लागू किया गया है:

public static boolean checkLowerStructuralSupport(Location location) { 

    boolean hasSupport = false; 

    Location supportingLocation = new Location(location.getX(), location.getY(), location.getZ() - 1); 

    System.out.println(_levels.get(supportingLocation.getZ()).getLevelSites2().get(supportingLocation)); //works 

    if (_levels.get(supportingLocation.getZ()).getLevelSites2().containsKey(supportingLocation)) { 
     hasSupport = true; 
    } else { 
     hasSupport = false; 
    } 

    return hasSupport; 
} 

यहां स्थान वर्ग के लिए कोड है। यही है, यदि दो Location ऑब्जेक्ट्स प्रभावी रूप से बराबर हैं, तो उन्हें एक सामान्य हैश कोड साझा करना चाहिए और उनकी equals विधि true वापस करनी चाहिए।

+1

लेकिन फिर क्यों() काम और इसमें शामिल होगा() नहीं? – butterchicken

+1

@butterchicken: शायद प्राप्त करें() मान प्राप्त करने के लिए "हैशकोड" अनुकूलन का उपयोग नहीं कर रहा है, जबकि "includeKey" है। –

+0

मैंने अन्य तरीकों से प्रभावी ढंग से शामिल किया है .... frazzled – burntsugar

2

स्थान कक्षा में, सुनिश्चित करें कि आप hashCode और तरीकों के बराबर होती है अधिभावी कर रहे हैं।

यदि आप हैं, तो क्या आप उन्हें पोस्ट कर सकते हैं?

1

get() और containsKey()Location कक्षा hashCode() विधि का उपयोग कर रहे हैं। equals() विधि तब तक नहीं बुलाई जाती है जब तक कि हैश टक्कर न हो। (इस प्रकार, HashMap के get() हर स्थिति में equals() का उपयोग करेगा नहीं।)

अपने Location वर्ग के लिए, आप संयोग से किया hashCode() के अपने स्वयं के संस्करण को लागू करने की होती हैं? hashCode() विधि सावधानीपूर्वक लागू की जानी चाहिए। जोशुआ ब्लोच ने पुस्तक में सभी विवरणों का वर्णन किया है प्रभावी जावा, जिनमें से ऑनलाइन भाग हैं ... मैं उन नमूना अध्यायों का लिंक पाउंगा: Effective Java Sample Chapters। आप अध्याय 3.

जैसा कि मैंने सवाल पर टिप्पणी में पूछा था, आपका _levels चर कहां से आता है? मुझे यह विधि और आपके नामकरण के अंदर घोषित नहीं किया गया है (अंडरस्कोर उपसर्ग, क्या आप उस सम्मेलन को किसी अन्य भाषा से आयात कर रहे हैं?) बताता है कि यह इस विधि के बाहर "रहता है"। शायद अन्य कोड इसे निष्पादन के दौरान बदल रहा है? जब आप इसे हल करते हैं तो कृपया हमें बताएं; ये रोमांच मेरी जान ले रहा है।

+2

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

+0

नहीं - जेडीके स्रोत में देखें: लाइन में कुंजी कुंजी समानता (जब तक कि मुख्य पहचान समान नहीं है) प्राप्त करें और शामिल है (अगर। _.hh == हैश और& ((k = e.key) == कुंजी || key.equals (k))) – paulcm

+1

एक हैश टकराव होने पर बराबर के दौरान कॉल किया जाएगा। –

2

शामिल है कुंजी कुंजी सेट में प्रविष्टियों के साथ परम की तुलना करने के लिए विधि बराबर का उपयोग करता है। इसलिए स्थान वर्ग की एक समान विधि होनी चाहिए जो अच्छी है। Java.lang.Object में डिफ़ॉल्ट बराबर विधि केवल तभी सत्य होती है जब दोनों ऑब्जेक्ट एक ही ऑब्जेक्ट होते हैं। इस मामले में आपके पास शायद 2 अलग-अलग उदाहरण हैं जिन्हें तुलना करने की आवश्यकता है और एक कस्टम बराबर विधि की आवश्यकता है।

1

समस्याओं से बचने के लिए, आपके equals() और hashCode() विधियों को सुसंगत होना चाहिए और आवश्यकताओं के अनुरूप होना चाहिए (जैसा कि अन्यत्र उल्लेख किया गया है)।

साथ ही, hashCode() चाहिए नहीं परिवर्तनशील सदस्यों पर भरोसा करते हैं, अन्यथा आपके परिकलित हैश कोड बदल सकते हैं, और इस HashMap की आंतरिक कार्यप्रणाली को प्रभावित करता है। इससे Hash* संग्रहों से सामान पुनर्प्राप्त करने में असमर्थता दिखाई देगी।

5

जैसा कि यहां दिया गया है, आपको बराबर (ऑब्जेक्ट) विधि को ओवरराइड करना होगा।

कारण (ऑब्जेक्ट) काम करने का कारण यह है कि हैश मैप आपके स्थान वर्ग के लिए हैश की गणना करेगा और ऑब्जेक्ट को हैकोड पॉइंट्स लौटाएगा।

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

HashMap

/** 
* Check for equality of non-null reference x and possibly-null y. 
*/ 
static boolean eq(Object x, Object y) { 
    return x == y || x.equals(y); 
} 

से वस्तु

public boolean equals(Object obj) { 
    return (this == obj); 
    } 

से बराबर है के जावाडोक से

The Class वस्तु के लिए विधि को लागू करता है सबसे discriminat के बराबर होती है वस्तुओं पर संभव समकक्ष संबंध; यानी, किसी भी गैर-शून्य संदर्भ मान x और y के लिए, यह विधि सही होती है अगर केवल और यदि x और y एक ही ऑब्जेक्ट को संदर्भित करता है (x == y मान सत्य है)।

ध्यान दें कि यह आम तौर पर आवश्यक ओवरराइड करने के लिए hashCode विधि जब भी इस विधि ओवरराइड की गई है, इसलिए के रूप में hashCode विधि है, जिसमें कहा गया है कि बराबर वस्तुओं बराबर हैश कोड होना आवश्यक है के लिए सामान्य अनुबंध को बनाए रखने ।

+3

मैं गलत हो सकता था, लेकिन मुझे पूरा यकीन है कि (...) समानता के लिए कुंजी (स्थान) की तुलना करेगा, और केवल इसे तुरंत ढूंढने के लिए हैश का उपयोग करता है (तुलना की संख्या को कम करें)। यह एक ही हैश (जो पूरी तरह से कानूनी है) के साथ कई वस्तुओं के बीच अंतर कैसे होगा। –

2

केवल एक चीज मैं उस के बारे में सोच सकते हैं कि इस का कारण होगा यदि supportingLocation के राज्य किसी भी तरह get(...) कॉल और containsKey(...) के बीच उत्परिवर्तित जा रहा है।

कोड मान लिया जाये कि स्निपेट को तैनात सटीक कोड है कि समस्याओं के कारण है, केवल जगह यह हो सकता है Location#getZ(...), Location#hashCode() या Location#equals(Object) की अगर एक स्थान के राज्य mutates (या स्थान निर्माता, या इन तरीकों में से एक शुरू होता है एक धागा जो यादृच्छिक रूप से स्थान उदाहरण की स्थिति को बदलता है, लेकिन मुझे लगता है कि हम इसे बाहर कर सकते हैं)।

क्या आप सत्यापित कर सकते हैं कि उपर्युक्त विधियों में से कोई भी supportingLocation इंस्टेंस की स्थिति बदल रहा है? जबकि मैं Location कक्षा से खुद परिचित नहीं हूं, मैं अनुमान लगाता हूं कि इस तरह की एक कक्षा आदर्श रूप से अपरिवर्तनीय होगी।

संपादित करें: स्पष्ट करने के लिए, जब मैं कहता हूँ कि Location#getZ() आदि स्थान परिवर्तनशील नहीं कर रहे हैं, मैं क्या मतलब है:

Location x = new Location(1,2,3); 
Location y = new Location(1,2,3); 

boolean eq1 = x.equals(y); 
int hash1 = x.hashCode(); 
x.getZ(); // this should *not* mutate the state of x 
boolean eq2 = x.equals(y); 
int hash2 = x.hashCode(); 

अंत में, eq1 eq1 के बराबर होना चाहिए, और hash1 होना चाहिए हैश 2 के बराबर।यदि यह मामला नहीं है, तो getZ() x (या बराबर, या हैशकोड, या इससे भी बदतर, उन विधियों को पूरी तरह से बंद कर देता है) को बदल रहा है, और परिणामस्वरूप आपके द्वारा देखे गए व्यवहार का परिणाम होगा।

+0

मैंने जो कोड पोस्ट किया है वह सटीक कार्यान्वयन है। स्थान वर्ग में म्यूटेटर विधियां हैं। चीयर्स। – burntsugar

+0

उत्परिवर्तन कोई फर्क नहीं पड़ता। बराबर और हैशकोड को ओवरराइड नहीं किया गया है, इसलिए डिफ़ॉल्ट संस्करणों का उपयोग किया जाएगा, और वे केवल ऑब्जेक्ट की स्थिति नहीं, सूचक को देखते हैं। – finnw

+0

हाँ, मैं सहमत हूं, मेरा उत्तर पूर्ण स्थान स्रोत कोड पोस्ट करने से पहले पोस्ट किया गया था। मुझे अब क्या गड़बड़ है, शायद एक दुष्ट 'मानचित्र' कार्यान्वयन, या 'getLevelSites2()' में एक बग के नुकसान में है। –

1

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

केवल वास्तविक अंतर है, और के रूप में बताया गया है, यह एक तुच्छ अशक्त जांच है, की तुलना में है:

प्राप्त करें:

((k = e.key) == key || key.equals(k)) 

containsKey:

((k = e.key) == key || (key != null && key.equals(k))) 

जहां ई हैश मैप के लिए एंट्री प्रकार है।

तो, यदि आपके पास हैशकोड() और/या बराबर() के मजबूत कार्यान्वयन नहीं हैं तो आपको एक समस्या होगी। इसके अतिरिक्त, अगर आपकी चाबियाँ उत्परिवर्तित की गईं (मुझे लगता है कि आपने कक्षा फ़ील्ड को अंतिम घोषित नहीं किया है) तो आपको कोई समस्या हो सकती है।

निम्न उदाहरण लें:

public class HashMapTest { 
    static class KeyCheck { 
     int value; 
     public KeyCheck(int value) { this.value = value; } 
     public void setValue(int value) { this.value = value; } 
     @Override public int hashCode() { return value; } 
     @Override public boolean equals(Object o) { 
      return ((KeyCheck)o).value == this.value; 
     } 
    } 

    public static void main(String args[]) { 
     HashMap<KeyCheck, String> map = new HashMap<KeyCheck, String>(); 
     KeyCheck k1 = new KeyCheck(5); 
     KeyCheck k2 = new KeyCheck(5); 

     map.put(k1, "Success"); 

     System.out.println("Key: " + k1 + " Get: " + map.get(k1) + 
          " Contains: " + map.containsKey(k1)); 
     System.out.println("Key: " + k2 + " Get: " + map.get(k2) + 
          " Contains: " + map.containsKey(k2)); 

     k1.setValue(10); 

     System.out.println("Key: " + k1 + " Get: " + map.get(k1) + 
          " Contains: " + map.containsKey(k1)); 
     System.out.println("Key: " + k2 + " Get: " + map.get(k2) + 
          " Contains: " + map.containsKey(k2)); 
    } 
} 

यह प्रिंट आउट देगा:

कुंजी: HashMapTest $ KeyCheck @ 5 प्राप्त करें: सफलता है: सच
कुंजी: HashMapTest $ KeyCheck @ 5 प्राप्त करें : सफलता में शामिल हैं: सत्य
कुंजी: हैश मैपटेस्ट $ कीचेक @ एक प्राप्त करें: शून्य में शामिल हैं: झूठी
कुंजी: हैश मैपटेस्ट $ कीचेक @ 5 प्राप्त करें: शून्य में शामिल हैं: झूठी

जैसा कि आप देख सकते हैं, इस मामले में उत्परिवर्तन ने हैशकोड() को बदलने के लिए, जो सब कुछ बर्बाद कर दिया।

+0

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

0

मैं कुछ समय लगता है कि आप हैश कोड और कभी कभी की जरूरत है ताकि मैं इस तरह से आप की जाँच जब आप करने के लिए सभी वस्तुओं आप चाहते हैं के लिए हैश कोड को बदलने खरीदने चाहते हैश कोड के बदल सकते हैं में सोच भी नहीं 0

public class sample(){ 
    @JsonIgnore 
    private int hashCode = super.hashCode(); 

    public void setHashCode(int hashCode){ 
     this.hashCode = hashCode; 
    }  

    @Override 
    public int hashCode(){ 
     return this.hashCode; 
    }  

    @Override 
    public boolean equals(Object obj) { 
     if (obj == null) { 
      return false; 
     } 
     if (getClass() != obj.getClass()) { 
      return false; 
     } 
     final ReflectObject other = (ReflectObject) obj; 
     if (this.hashCode != other.hashCode) { 
      return false; 
     } 
     return true; 
    } 
} 
संबंधित मुद्दे