2011-07-06 17 views
10

मुझे ओवररेडिन बराबर का सही उपयोग करने के लिए ArrayList प्राप्त करने में कोई समस्या है। समस्या यह है कि मैं केवल एक कुंजी क्षेत्र के लिए परीक्षण करने के लिए बराबर का उपयोग करने की कोशिश कर रहा हूं, और सही क्षेत्र के साथ किसी ऑब्जेक्ट के अस्तित्व के परीक्षण के लिए ArrayList.contains() का उपयोग कर रहा हूं। यहाँ एक उदाहरणArrayList ओवरराइड का उपयोग नहीं कर रहा है

public class TestClass { 
    private static class InnerClass{  
    private final String testKey; 
    //data and such 

    InnerClass(String testKey, int dataStuff) { 
     this.testKey =testKey; 
     //etc 
    } 
    @Override 
    public boolean equals (Object in) { 
     System.out.println("reached here"); 
     if(in == null) { 
     return false; 
     }else if(in instanceof String) { 
     String inString = (String) in; 
     return testKey == null ? false : testKey.equals(inString); 
     }else { 
     return false; 
     }  
    }  
    } 

    public static void main(String[] args) {  
    ArrayList<InnerClass> objectList = new ArrayList<InnerClass>(); 
    //add some entries 
    objectList.add(new InnerClass("UNIQUE ID1", 42)); 
    System.out.println(objectList.contains("UNIQUE ID1")); 
    }  
} 

क्या चिंता मुझे यह है कि न केवल मैं उत्पादन पर झूठे हो रही है, लेकिन मैं भी "यहाँ तक पहुँच" उत्पादन नहीं मिल रहा है।

क्या किसी के पास कोई विचार है कि इस ओवरराइड को पूरी तरह से अनदेखा क्यों किया जा रहा है? क्या ओवरराइड और आंतरिक कक्षाओं के साथ कुछ सूक्ष्मता है जो मुझे नहीं पता?

संपादित करें: साइट के साथ समस्याएं होने के कारण मैं उत्तर को चिह्नित नहीं कर सकता। त्वरित प्रतिक्रिया के लिए धन्यवाद: हां मेरे हिस्से पर एक निरीक्षण है कि यह स्ट्रिंग है। असमान thta कहा जाता है, मेरा कस्टम नहीं। मुझे लगता है कि यह अब

उत्तर

15

यदि आप ArrayList के स्रोतों की जांच करते हैं, तो आप देखेंगे कि यह अन्य ऑब्जेक्ट के equals पर कॉल करता है।आपके मामले में यह फोन करेगा String "UNIQUE ID1" की equals जो कि अन्य वस्तु की जाँच करेगा प्रकार String की नहीं है और सिर्फ false रिटर्न:

objectList.contains(new InnerClass("UNIQUE ID1")) 
:

public boolean contains(Object o) { 
    return indexOf(o) >= 0; 
} 

public int indexOf(Object o) { 
    ...  
    for (int i = 0; i < size; i++) 
    if (o.equals(elementData[i])) 
     return i; 
    ... 
    return -1; 
} 

InnerClass केवल जिसमें id साथ अपने मामले कॉल contains के लिए

को InnerClass के लिए लागू करना न भूलें जो केवल id की तुलना करता है।

+0

धन्यवाद। नए InnerClass() के बारे में यह सुझाव वास्तव में भी सहायक था। :) – Sufian

+1

मेरी राय में indexOf का कार्यान्वयन अन्य तरीकों से होना चाहिए: elementData [i] .equals (o) ... – marcolopes

0

के लिए पुरानी शैली की जांच है, हालांकि आपके प्रश्न का उत्तर नहीं दे रहा है, कई संग्रह hashcode() का उपयोग करते हैं। आपको equals() के साथ "सहमत" करने के लिए भी ओवरराइड करना चाहिए।

असल में, आप हमेशाequals और hashcode दोनों एक साथ लागू करना चाहिए, और वे हमेशा एक दूसरे के अनुरूप होना चाहिए।

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

विशेष रूप से, इस संग्रह पर कई संग्रहों का पालन किया जा रहा है - व्यवहार अन्यथा अनिर्धारित है।

+1

हालांकि यह सच है कि आपको दोनों को लागू करना चाहिए, यह इस विशिष्ट मामले में मदद नहीं करता है, क्योंकि 'ऐरेलिस्ट' किसी भी तरह से हैश-आधारित नहीं है: यह 'हैशकोड() 'कार्यान्वयन की परवाह नहीं करता है। –

+0

'ऐरेलिस्ट' 'हैशकोड' –

+0

ठीक नहीं है। मैंने अपना जवाब "लेटा" किया। आप दोनों अच्छे अंक – Bohemian

3

आप एक तर्क है कि एक String और एक InnerClass नहीं है साथ contains लागू कर रहे हैं:

System.out.println(objectList.contains("UNIQUE ID1")) 

मेरी JDK में:

public class ArrayList { 

    public boolean contains(Object o) { 
    return indexOf(o) >= 0; 
    } 

    public int indexOf(Object o) { 
    if (o == null) { 
     // omitted for brevity - aix 
    } else { 
     for (int i = 0; i < size; i++) 
     if (o.equals(elementData[i])) // <<<<<<<<<<<<<<<<<<<<<< 
      return i; 
    } 
    return -1; 
    } 
} 

नोट कैसे indexOf कॉल o.equals()। आपके मामले में, o एक String है, इसलिए आपका objectList.containsString.equals का उपयोग करेगा और InnerClass.equals नहीं होगा।

7

the JavaDoc of List.contains(o) के अनुसार, यह true

वापस जाने के लिए परिभाषित किया गया है, तो और इस सूची में कम से कम एक तत्व e ऐसी है कि (o==null ? e==null : o.equals(e)) शामिल करते हों।

ध्यान दें कि यह परिभाषा कॉल o पर equals, जो पैरामीटर और नहीं तत्व List में है।

इसलिए String.equals() को कॉल किया जाएगा और InnerClass.equals() नहीं कहा जाएगा।

यह भी ध्यान रखें the contract for Object.equals() कहा गया है कि कि

यह सममित है: किसी भी गैर-शून्य संदर्भ मूल्यों x और y, x.equals(y) के लिए true लौटना चाहिए यदि और केवल यदि y.equals(x) रिटर्न true

लेकिन आप इस बाधा, new TestClass("foo", 1).equals("foo") रिटर्न true लेकिन "foo".equals(new TestClass("foo", 1)) हमेशा false वापस आ जाएगी के बाद से उल्लंघन करते हैं।

दुर्भाग्य से इसका मतलब है कि आपका उपयोग केस (एक कस्टम क्लास जो कि किसी अन्य मानक वर्ग के बराबर हो सकता है) को पूरी तरह से अनुरूप तरीके से लागू नहीं किया जा सकता है।

आप अभी भी कुछ इस तरह करना चाहते हैं तो, आप अपने सभी संग्रह कक्षाएं बहुत ध्यान के विनिर्देश (और कभी कभी कार्यान्वयन) पढ़ सकते हैं और इस जैसे नुकसान के लिए जाँच करने के लिए होगा।

+0

बहुत लंबे समय तक काम कर रहा था। जब आप मूल बातें भूलना शुरू करते हैं, या एपीआई विनिर्देशों को गलत तरीके से पढ़ना शुरू करते हैं तो कभी भी अच्छा संकेत नहीं। मुझे टेस्ट ऑब्जेक्ट बनाने के लिए नए इनर क्लास (स्ट्रिंग टेस्टकी) का कन्स्ट्रक्टर रखने का काम मिल गया है, लेकिन वास्तव में डेटा को शून्य/0s के रूप में। –

2

आम तौर पर, आपको hashCode() को ओवरराइड करने की आवश्यकता है लेकिन यह यहां मुख्य समस्या नहीं है। आपके पास असममित equals(..) विधि है।

यह सममित है: डॉक्स यह स्पष्ट यह सममित होना चाहिए कि बनाने के लिए किसी भी गैर-शून्य संदर्भ वेल्यू एक्स और वाई, x.equals (y) यदि सच और केवल यदि y.equals (एक्स लौटना चाहिए) सच देता है।

और जो आप देखते हैं वह टूटा अनुबंध के कारण एक अप्रत्याशित व्यवहार है।

public static boolean containsString(List<InnerClass> items, String str) { 
    for (InnerClass item : items) { 
     if (item.getTestKey().equals(str)) { 
      return true; 
     } 
    } 
    return false; 
} 

आप अमरूद के Iterables.any(..) विधि के साथ एक ऐसी ही बात कर सकते हैं::

एक उपयोगिता विधि है कि सभी वस्तुओं iterates और स्ट्रिंग पर equals(..) साथ सत्यापित करता बनाएं

final String str = "Foo"; 
boolean contains = Iterables.any(items, new Predicate<InnerClass>() { 
    @Override 
    public boolean apply(InnerClass input){ 
     return input.getTestKey().equals(str); 
    } 
} 
1

आपका बराबरी कार्यान्वयन गलत है । आपका पैरामीटर String नहीं होना चाहिए। यह InnerClass होना चाहिए।

public boolean equals(Object o) { 
    if (this == o) return true; 
    if (!(o instanceof InnerClass) return false; 
    InnerClass that = (InnerClass)o; 
    // check for null keys if you need to 
    return this.testKey.equals(that.testKey); 
} 

(ध्यान दें कि instanceof null रिटर्न झूठी है, तो आप अशक्त पहले की जांच करने की जरूरत नहीं है)।

फिर आप का उपयोग कर अपने सूची में एक बराबर वस्तु के अस्तित्व के लिए परीक्षण होगा:

objectList.contains(new InnerClass("UNIQUE ID1")); 

लेकिन क्या तुम सच में स्ट्रिंग कुंजी द्वारा InnerClass के लिए जाँच करना चाहते हैं, क्यों Map<String,InnerClass> बजाय का उपयोग नहीं?

+0

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

0

आपके कोड के साथ कुछ समस्याएं हैं। मेरे सुझाव बराबरी अधिभावी से बचने के लिए पूरी तरह से अगर आप इसे से परिचित नहीं हैं और यह बहुत की तरह एक नया कार्यान्वयन में विस्तार करने के लिए किया जाएगा ...

class MyCustomArrayList extends ArrayList<InnerClass>{ 

    public boolean containsString(String value){ 
     for(InnerClass item : this){ 
      if (item.getString().equals(value){ 
       return true; 
      } 
     } 
     return false; 
    } 

} 

तो फिर तुम

List myList = new MyCustomArrayList() 
myList.containsString("some string"); 
की तरह कुछ कर सकते हैं

मैं इसका सुझाव देता हूं क्योंकि यदि आप बराबर को ओवरराइड करते हैं तो हैशकोड को ओवरराइड करना चाहिए और ऐसा लगता है कि आपको इस क्षेत्र में थोड़ा ज्ञान नहीं है - इसलिए मैं इसे टाल दूंगा।

इसके अलावा, इसमें विधि समान विधि को कॉल करती है, यही कारण है कि आप "यहां पहुंचे" को देख रहे हैं। दोबारा यदि आप कॉल प्रवाह को समझ नहीं पाते हैं तो मैं इसे टाल दूंगा।

+0

मैं कॉल प्रवाह को समझता हूं, लेकिन याद किया कि यह InnerClass.equals की बजाय String.equals का उपयोग कर रहा था। चूंकि ArrayList हैश आधारित नहीं है, मुझे स्निपेट में हैशकोड शामिल करने की आवश्यकता नहीं है। स्वाभाविक रूप से मैं एक हैशकोड ओवरराइड शामिल करता हूं, भले ही इसे यहां की सभी चीज़ों को testKey.hashCode() –

0

दूसरी तरफ, यदि आप अपना कोड बदलते हैं तो आपकी समान विधि को कॉल किया जाता है। उम्मीद है कि यह अवधारणा को मंजूरी दे दी है।

package com.test; 

import java.util.ArrayList;  
import java.util.List; 

public class TestClass { 
    private static class InnerClass{  
     private final String testKey; 
     //data and such 

     InnerClass(String testKey, int dataStuff) { 
      this.testKey =testKey; 
      //etc 
     } 

     @Override 
     public boolean equals (Object in1) { 
      System.out.println("reached here"); 
      if(in1 == null) { 
       return false; 
      }else if(in1 instanceof InnerClass) { 
       return ((InnerClass) this).testKey == null ? false : ((InnerClass) this).testKey.equals(((InnerClass) in1).testKey); 
      }else { 
       return false; 
      }  
     }  
    } 

    public static void main(String[] args) {  
     ArrayList<InnerClass> objectList = new ArrayList<InnerClass>(); 
     InnerClass in1 = new InnerClass("UNIQUE ID1", 42); 
     InnerClass in2 = new InnerClass("UNIQUE ID1", 42); 

     //add some entries 
     objectList.add(in1); 
     System.out.println(objectList.contains(in2)); 
    }  
} 
0

के रूप में कई पदों कहा है, समस्या list.indexOf (obj) समारोह obj, सूची में नहीं मदों की "बराबर है" कॉल करता है।

मुझे एक ही समस्या थी और "इसमें()" मुझे संतुष्ट नहीं किया, क्योंकि मुझे यह जानने की जरूरत है कि तत्व कहां है! मेरा अपमान केवल तुलना करने के लिए पैरामीटर के साथ एक खाली तत्व बनाना है, और उसके बाद indexOf को कॉल करें।

इस तरह एक समारोह को लागू करें,

public static InnerClass empty(String testKey) { 
    InnerClass in = new InnerClass(); 
    in.testKey =testKey; 
    return in; 
} 

और फिर, इस तरह indexOf फोन:

ind position = list.indexOf(InnerClass.empty(key)); 
0

अपने कोड में दो त्रुटियां नहीं हैं।

पहला: "ऑब्जेक्टलिस्ट" ऑब्जेक्ट पर "शामिल" विधि को पैरामीटर के रूप में एक नया इनर क्लास ऑब्जेक्ट पास करना चाहिए।

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

@Override 
    public boolean equals (Object in) { 
     System.out.println("reached here"); 
     if(in == null) { 
     return false; 
     }else if(in instanceof InnerClass) { 
     String inString = ((InnerClass)in).testKey; 
     return testKey == null ? false : testKey.equals(inString); 
     }else { 
     return false; 
     }  
    } 
0

इस पोस्ट में पहले लिखा गया था से पहले जावा 8 उपलब्ध था, लेकिन अब है कि यह 2017 के बजाय List.containts (...) विधि का उपयोग कर आप नए जावा 8 रास्ता इस तरह उपयोग कर सकते हैं की है:

System.out.println(objectList.stream().filter(obj -> obj.getTestKey().equals("UNIQUE ID1")).findAny().isPresent()); 

और अपने testKey क्षेत्र के लिए अपने TestClass एक गेटर दे:

public String getTestKey() { 

    return testKey; 
} 

इस दृष्टिकोण का लाभ आप बराबर या हैश विधि और you'l को संशोधित करने की जरूरत नहीं है कि है मैं अपने साथियों के लिए एक मालिक की तरह लग रहा हूँ!

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