2014-09-21 7 views
14

हालांकि इस सवाल से गुजर रही: "Checking if an object is contained within a linkedlist", मैंने महसूस किया कि उपयोगकर्ता प्रकार LinkedList की एक LinkedList की विधि शामिल करने के लिए एक स्ट्रिंग तर्क पारित करने के लिए कोशिश कर रहा था:सूची विधि टाइप सुरक्षित नहीं होता है

LinkedList<LinkedList> list = new LinkedList<LinkedList>(); 

    list.contains("String"); 

यह नहीं करता है किसी भी संकलन त्रुटि को फेंक न दें क्योंकि 'शामिल' विधि java.lang.Object स्वीकार करती है और इसे स्ट्रिंग मान पास करने की अनुमति है।

तो जिज्ञासा से बाहर, मैं समझना चाहता था कि यह विधि 'ऑब्जेक्ट' को स्वीकार करने के लिए क्यों चुनी गई थी, जब इसे केवल सूची प्रकार (केवल जोड़ने की तरह) स्वीकार करने के लिए प्रतिबंधित किया जा सकता था। क्या यह जेनेरिक के पूरे उद्देश्य को हरा नहीं रहा है यानी "संकलित समय पर मजबूत प्रकार की जांच"?

+2

यहाँ इस विषय http://www.javaworld.com/article/2073330/the-contains-trap-in-java-collections.html – nem035

+0

संबंधित पर एक अच्छा पढ़ा है, या कहें की नकल http://stackoverflow.com/questions/857420/what-are-the-reasons-why-map-getobject-key-is-not-fully-generic और http: // stackoverflow।कॉम/प्रश्न/10479 9/क्यों-हैंन्ट-जावा-संग्रह-हटाने-विधियों-जेनेरिक – Marco13

उत्तर

-1

बस पिछड़े संगतता के लिए। यद्यपि जनरेट एक संग्रह की सामग्रियों को एक समान प्रकार में प्रतिबंधित करने के लिए उपयोगी हैं, फिर भी यदि आप चयन करते हैं तो संग्रह में विषम ऑब्जेक्ट्स रखने के लिए यह एक वैध उपयोग केस है।

public static void main(String[] args) 
{ 
    List<String> homogeneousStringList = new ArrayList<String>(); 

    homogeneousStringList.add("Foo"); 
    homogeneousStringList.add("Bar"); 

    List heterogeneousObjectList = new ArrayList(); 

    heterogeneousObjectList.add("Foo"); 
    heterogeneousObjectList.add(Integer.valueOf(1)); 
    heterogeneousObjectList.add(new Date()); 

    System.out.println(homogeneousStringList.toString()); 
    System.out.println(heterogeneousObjectList.toString()); 
} 

निम्नलिखित उत्पादन का उत्पादन:

[फू, बार]

[फू, 1, सूर्य सितं, 21 00:36:59 एमडीटी 2014]

+0

और आपका स्रोत? !!! –

+1

यह बिंदु नहीं है, यदि आप जेनेरिक प्रकार निर्दिष्ट नहीं करते हैं, तो यह डिफ़ॉल्ट रूप से ऑब्जेक्ट होगा। और वास्तव में विरासत मौजूद होने के बाद से प्रत्येक सूची विषम है। – kamil09875

8

मान लीजिए कि आप एक करते हैं BankAccountAccountId द्वारा पहचाना गया (दोनों कक्षाएं हैं, न ही दूसरे को विस्तारित करना)।

मान लें अब आपके पास LinkedList<BankAccount> accounts; है और यह देखना चाहते हैं कि किसी दिए गए आईडी के साथ कोई खाता है या नहीं।

अब, AccountId.equals()BankAccount स्वीकार कर सकता है और खाता की आईडी के विरुद्ध खुद की तुलना कर सकता है। इसके साथ, आप accounts.contains(account_id) पर कॉल करने में सक्षम होंगे और यह केवल काम करेगा, भले ही पर तर्क एक प्रकार का है जो संग्रह के प्रकार से पूरी तरह से असंबंधित नहीं है।

+0

आप अकाउंट आईडी द्वारा पहचाने गए बैंक अकाउंट कहते हैं, लेकिन न तो दूसरे को विस्तारित करते हैं .. वास्तव में इसका पालन नहीं करते हैं। क्या आप इसे और अधिक जानकारी प्रदान कर सकते हैं, ताकि इसे बेहतर समझ सकें? – Gaurav

+0

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

+7

मैं इसे दो अलग-अलग वर्गों को लागू करने के लिए ** अत्यधिक ** संदिग्ध मानता हूं जिस तरह से एक वर्ग का एक उदाहरण दूसरे वर्ग के उदाहरण के लिए 'बराबर' हो सकता है। इस तरह के एक कार्यान्वयन के साथ कई उचित उपयोग पैटर्न तोड़ सकता है। (यह उन वर्गों को संदर्भित करता है जो उनके द्वारा कार्यान्वित एक सामान्य इंटरफ़ेस के संदर्भ में "बराबर" नहीं हैं) – Marco13

1

सभी में से प्रत्येक विधि अंतर्निहित संग्रह को संशोधित नहीं करती है, इसलिए इसमें विधि जोड़ने जैसी सख्त आवश्यकता नहीं है।

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

एक उदाहरण:

List<A> myList = new LinkedList<A>(); 
... 
B b = new B(); 
myList.contains(b); //expected true if 'value' attribute is equal. 


class A { 
    int value; 
    public boolean equals(Object object){ 
     if(object instanceof A && ((A)object).getValue() == this.value) 
     return true; 
     else if(object instanceof B && ((B)object).getValue() == this.value) 
     return true; 
     else 
     return false; 

} 

और इसी तरह

class B { 
    int value; 
    public boolean equals(Object object){ 
     if(object instanceof A && ((A)object).getValue() == this.value) 
     return true; 
     else if(object instanceof B && ((B)object).getValue() == this.value) 
     return true; 
     else 
     return false; 

} 
3

सरल ... LinkedList वास्तव में एक वस्तु है।

  • CustomMapItem 1:

    इसके अलावा,

    आप अपने लिंक किए गए सूची में से प्रत्येक के लिए एक नक्शा है कहो LinkedList 1

  • CustomMapItem 2: LinkedList 2
  • CustomMapItem 3: LinkedList 3

क्योंकि पैरामीटर के रूप में ऑब्जेक्ट लेता है, तो आप कस्टम मैपइटम के लिए अपने equals() और hashcode() विधियों को सेट करने में सक्षम हैं ताकि आप अपनी संबंधित लिंक्डलिस्ट ढूंढ सकें।

+0

> यदि आप जेनेरिक लेने के लिए शामिल विधि सेट करते हैं तो आप इसकी ऑब्जेक्ट गुणों को हटा देंगे। इस प्रकार, आप अपना खुद का हैशकोड() और बराबर() विधियों को बनाने की क्षमता खो देंगे <<<< क्या आप समझा सकते हैं? मैं पीछा नहीं कर रहा हूँ। –

+0

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

4

के लिए विशिष्ट विवरण है विधि का कहना है:

रिटर्न सच अगर और सिर्फ़ अगर इस संग्रह कम से कम एक तत्व ई ऐसी है कि (o==null ? e==null : o.equals(e)) [डॉक्स ओरेकल] [1]

हालांकि शामिल , यह भी कहता है कि यदि संग्रह निर्दिष्ट तत्व का प्रकार इस संग्रह के साथ असंगत है, तो संग्रह NullPointerException फेंक सकता है यदि संग्रह शून्य तत्वों या ClassCastException को अनुमति नहीं देता है। इन्हें optional के रूप में चिह्नित किया गया है।

इसके अलावा, यह भी कहता है कि:

संग्रह फ्रेमवर्क इंटरफेस में कई तरीके बराबरी विधि के मामले

लेकिन में परिभाषित कर रहे हैं:

इस विनिर्देशन नहीं होना चाहिए यह इंगित करने के लिए माना जाता है कि एक गैर-शून्य तर्क के साथ संग्रह.contains का आह्वान ओ oequals (ई) किसी तत्व के लिए लागू किया जाएगा e

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

मैं एक उदाहरण के साथ नवीनतम समझाएंगे:

public class A { 

    public void initialize() { 
     // Lots of code and heavy initialization 
    } 

    public String id; 

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

    @Override 
    public boolean equals(Object o) { 
     return this.hashCode() == o.hashCode(); 
    } 
} 

और फिर:

SomeCollection<A> collection = new SomeCollection<A>(); 

// Create an element and add it to the collection 
A a = new A(); 
a.initialize(); // Heavy initialization 
element.id = "abc"; 
collection.add(a); 

// Check if the collection contains that element 

// We create a second object with the same id, but we do not initialize it 
A b = new A(); 
b.id = "abc"; 

// This works for many common collections (i.e. ArrayList and HashSet) 
collection.contains(b); 

वास्तव में, वहाँ indexOf(Object o) और remove(Object o) जो इस का पालन करें की तरह अधिक तरीके हैं। इसलिए मुझे नहीं लगता कि यह संगतता के लिए है, लेकिन यह इस तरह के समाधानों की अनुमति देने के उद्देश्य से बनाया गया है।

http://docs.oracle.com/javase/7/docs/api/java/util/Collection.html#contains(java.lang.Object)

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