2016-02-16 15 views
30

मेरे पास Test ऑब्जेक्ट्स हैं, जो स्ट्रिंग का उपयोग समानता जांच के रूप में करते हैं। मैं यह जांचने के लिए List.contains() का उपयोग करने में सक्षम होना चाहता हूं कि सूची में कोई ऑब्जेक्ट है जो एक निश्चित स्ट्रिंग का उपयोग करता है।List.contains() काम करता है .equals() काम करता है

सीधे शब्दों में:

Test a = new Test("a"); 
a.equals("a"); // True 

List<Test> test = new ArrayList<Test>(); 
test.add(a); 
test.contains("a"); // False! 

बराबर और हैश समारोह:

@Override 
public boolean equals(Object o) { 
    if (o == null) return false; 
    if (o == this) return true; 
    if (!(o instanceof Test)) { 
     return (o instanceof String) && (name.equals(o)); 
    } 
    Test t = (Test)o; 
    return name.equals(t.GetName()); 
} 

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

मैंने पढ़ा है, यह equals ओवरराइड करने के लिए की जरूरत है कि एक कस्टम वर्ग के लिए यकीन है कि contains काम करता है बनाने के लिए। इस प्रकार यह मेरे लिए बहुत अजीब बात है कि equals सच है, contains झूठी वापसी करता है।

मैं यह काम कैसे कर सकता हूं?

Full code

+1

एक वर्ग को केवल उसी वर्ग के साथ 'बराबर' का परीक्षण करना चाहिए। – ZhongYu

+8

आपके बराबर 'इक्विल्स' का विचार गलत है, आपको 'टेस्ट' की तुलना' टेस्ट' की तुलना करना चाहिए 'टेस्ट' – MadProgrammer

+0

केवल एक विपरीत रिवर्स काम करेगा, क्योंकि "एक" .equals (नया टेस्ट ("ए")) == झूठी' – njzk2

उत्तर

40

बस अपने Test के equals सच वापस आ सकते हैं जब आप इसे करने के लिए एक स्ट्रिंग पारित मतलब यह नहीं है कि String 'क्योंकि रों equals कभी सच लौटने जब आप इसे करने के लिए एक Test उदाहरण पारित करेंगे। वास्तव में, String के equals केवल true लौट सकते हैं जब उदाहरण यह करने के लिए पारित कर दिया एक और String है:

public boolean equals(Object anObject) { 
    if (this == anObject) { 
     return true; 
    } 
    if (anObject instanceof String) { // the passed instance must be a String 
     String anotherString = (String)anObject; 
     int n = value.length; 
     if (n == anotherString.value.length) { 
      char v1[] = value; 
      char v2[] = anotherString.value; 
      int i = 0; 
      while (n-- != 0) { 
       if (v1[i] != v2[i]) 
        return false; 
       i++; 
      } 
      return true; 
     } 
    } 
    return false; 
} 

ArrayList के contains कॉल indexOf जो खोजा उदाहरण के equals विधि (String "एक" का उपयोग करता है List के अपने उदाहरण), नहीं तत्व प्रकार (जो आपके मामले में Test है):

public int indexOf(Object o) { 
    if (o == null) { 
     for (int i = 0; i < size; i++) 
      if (elementData[i]==null) 
       return i; 
    } else { 
     for (int i = 0; i < size; i++) 
      if (o.equals(elementData[i])) // o in your case is a String while 
              // elementData[i] is a Test 
              // so String's equals returns false 
       return i; 
    } 
    return -1; 
} 
+9

'नया टेस्ट ("ए") बराबर ("ए")' सत्य 'देता है, जबकि "एक" .equals (नया टेस्ट ("ए"))' झूठा, अच्छा स्पष्टीकरण देता है! धन्यवाद इरान! –

+4

अहह, जो अब बहुत समझ में आता है। इसलिए अनिवार्य रूप से इसे हल करने का एकमात्र तरीका (और इसके बारे में जाने का एकमात्र सही तरीका) 'test.contains (नया टेस्ट ("ए")) लिखना है? – idlackage

+1

@idlackage हाँ, यह काम करेगा। – Eran

18

समस्या यह है किहैसच लौटने के लिए प्रलेखित है:

अगर और इस सूची में कम से कम एक तत्व ई ऐसा है कि (ओ == अशक्त शामिल केवल तो क्या होगा? ई == शून्य: o.equals (ई))।

(https://docs.oracle.com/javase/8/docs/api/java/util/List.html#contains-java.lang.Object- से)

ध्यान दें कि यह e.equals(o) के रूप में परीक्षण प्रदर्शन नहीं करता जो अपने परीक्षण काम करने के लिए क्या आवश्यक होगा। आपकी बराबर विधि कम से कम काम करने में विफल रहता है (जावा दस्तावेज़ों से शर्तों का उपयोग करके 'सममित रूप से')।

जावा दस्तावेजों है कि एक वर्ग के लिए equals() विधि इन नियमों का पालन करना होगा:

के बराबर होती है विधि में गैर-शून्य वस्तु संदर्भों पर एक तुल्यता संबंध लागू करता है:

  • यह कर्मकर्त्ता है: के लिए कोई भी गैर-शून्य संदर्भ मान x, x.equals(x) सत्य वापस करना चाहिए।
  • यह सममित है: किसी भी गैर-शून्य संदर्भ मूल्यों x और y के लिए, x.equals(y) सच यदि और केवल यदि y.equals(x) रिटर्न सच लौटना चाहिए।
  • यह सकर्मक है: किसी भी गैर-शून्य संदर्भ मूल्यों के लिए x, y, और z, अगर x.equals(y) रिटर्न सच और y.equals(z) रिटर्न सच है, तो x.equals(z) सच लौटना चाहिए।
  • यह संगत है: किसी भी गैर-शून्य संदर्भ मान x और y के लिए, x.equals(y) के कई आमंत्रण लगातार सत्य या लगातार लौटते हैं, बशर्ते ऑब्जेक्ट्स पर तुलना के बराबर उपयोग की जाने वाली कोई भी जानकारी संशोधित न हो।
  • किसी भी गैर-शून्य संदर्भ मूल्य x के लिए, x.equals(null) झूठी लौटना चाहिए।
25

equals() हमेशा commutative, अर्थात a.equals(b) और b.equals(a) हमेशा समान मान चाहिए होना चाहिए। या सममित, equals() की जावाडोक के रूप में यह कहता है:

  • यह कर्मकर्त्ता है:: किसी भी गैर-शून्य के लिए

    equals विधि में गैर-शून्य वस्तु संदर्भों पर एक तुल्यता संबंध लागू करता है संदर्भ मान x, x.equals(x)true वापस करना चाहिए।

  • यह सममित है: x और y, x.equals(y) किसी भी गैर-शून्य संदर्भ मूल्यों के लिए true यदि और केवल यदि y.equals(x) रिटर्न true लौटना चाहिए।
  • यह सकर्मक है: किसी भी गैर-शून्य संदर्भ मूल्यों के लिए x, y, और z, अगर x.equals(y) रिटर्न true और y.equals(z) रिटर्न true, तो x.equals(z)true लौटना चाहिए।
  • यह संगत है: किसी भी गैर-शून्य संदर्भ मूल्यों x और y, x.equals(y) के कई आमंत्रण के लिए लगातार true वापसी या लगातार लौट false, वस्तुओं पर equals तुलना में प्रयोग किया जाता में कोई जानकारी नहीं संशोधित किया गया है प्रदान की है।
  • किसी भी गैर-शून्य संदर्भ मूल्य x के लिए, x.equals(null)false लौटना चाहिए।

दुर्भाग्यवश, जावा रनटाइम लाइब्रेरी भी यह गलत हो जाता है। Date.equals(Timestamp)Timestamp में मौजूद नैनोसेकंड को अनदेखा करते हुए मिलीसेकंड मानों की तुलना करेगा, जबकि Timestamp.equals(Date)false देता है।

+0

+1 असममित 'बराबर रखना 'कोड को अनावश्यक रूप से नाजुक और बनाए रखने के लिए कठिन बना दिया जाएगा क्योंकि किस तरह से गोल परीक्षण किए जाते हैं। –

+0

जेडीके - मैप इंटरफ़ेस में भी बड़ी assymetry है। अगर आपने कभी सोचा है कि मानचित्र को पाने के बजाय मानचित्र क्यों प्राप्त हुआ है (ऑब्जेक्ट कुंजी) (के कुंजी) - वास्तव में गुजरने की अनुमति देने के लिए यादृच्छिक वर्ग जो कि के उदाहरणों के खिलाफ समानता को तोड़ने के लिए होता है। जावा सन के एक संस्करण में इस आदेश को बदल दिया गया है (इसलिए नक्शा के अंदर मूल्य की तुलना दूसरी तरफ की बजाय पास की कुंजी से की गई थी) और इसने उस पर बहुत से अनुप्रयोगों को तोड़ दिया है। –

4

आप

test.contains(new Test("a")); 

लिखना है तो यह निश्चित रूप से सच वापस आ जाएगी। आप टेस्ट की सूची में स्ट्रिंग ऑब्जेक्ट की जांच कर रहे हैं।

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