2013-08-15 4 views
5

क्यों बूलियन शामिल है (संग्रह <?> सी); प्रत्येक प्रकार के लिए संग्रह ढांचे की विधि की अनुमति है? लेकिन बूलियन एडएल (संग्रह <? ई> सी बढ़ाता है); के लिए अनुमति दें? ई बढ़ाता है। इसलिए, मैंने स्पष्टीकरण के लिए एक कार्यक्रम लिखा था। यहाँ मेरी कार्यक्रमबूलियन के डिजाइन निर्णय में सभी (संग्रह <?> सी) बनाम बूलियन एडएल (संग्रह <? extends E> सी); संग्रह ढांचे में

public class ContainAllTest { 
    // take ServiceDto 
    ArrayList<ServiceDto> resultList = new ArrayList<ServiceDto>(); 

    void Test() { 

     ServiceDto serviceDto = new ServiceDto(); 
     serviceDto.setName("test"); 
     resultList.add(serviceDto); 
     // another arraylist that takes String 
     ArrayList<String> resultList1 = new ArrayList<String>(); 
     resultList1.add("test"); 
     // no error, goes for run time.Contain all checking is done for two generic type ServiceDto and String: 
     resultList.containsAll(resultList1); 
     // error shown at compile time,as addAll take ServiceDto as generic type but the generic type for resultList1 take String: 
     resultList.addAll(resultList1);  
    } 

तो है, मेरे सवाल जब मैं resultList.containsAll (resultList1) का लाभ प्राप्त कर सकते है; (संग्रह <?> ग) जब सामान्य प्रकार मेरे मामले स्ट्रिंग कुछ बात गलत बूलियन containsAll जगह different.In और ServiceDto.Was है वहाँ बूलियन containsAll साथ (संग्रह <? फैली ई> ग)

+0

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

+0

@artbristol: हाँ, यह अनिवार्य रूप से एक ही सवाल है, और इसका एक बेहतर जवाब है। मैं इसे डुप्लिकेट के रूप में चिह्नित करने के लिए वोट दूंगा। –

+0

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

उत्तर

2

यह सीपीयू टिकों को बचाने के लिए इसका लाभ नहीं देना है। जेनरिक erased कंपाइलर द्वारा और कास्ट के साथ प्रतिस्थापित किया गया है।

addAll विधि प्रकार सुरक्षा आवश्यकताओं को ध्यान में रखना आवश्यक है। उपयोगकर्ता को केवल Collection<E> या E के कुछ उप-वर्ग को Collection<E> में जोड़ने की अनुमति दी जानी चाहिए।

आप AbstractCollection के लिए स्रोत कोड को देखो, तो आप इस विधि देखें:

public boolean addAll(Collection<? extends E> c) { 
    boolean modified = false; 
    for (E e : c) 
     if (add(e)) 
      modified = true; 
    return modified; 
} 

जब संकलित यह दिखेगा (कुछ)

public boolean addAll(Collection c) { 
    boolean modified = false; 
    for (Object e : c) 
     if (add((E)e)) 
      modified = true; 
    return modified; 
} 

यानी की तरह जोड़े जाने के पहले संग्रह के प्रत्येक तत्व को Object से E में जोड़ा जाने से पहले की आवश्यकता है।

containsAll विधि के लिए इससे कोई फर्क नहीं पड़ता। के रूप में equals विधि equals(Object other) के रूप में परिभाषित किया गया है आप सुरक्षित रूप से किसी अन्य Collection साथ यह कॉल कर सकते हैं और वहाँ ClassCastException रों का कोई खतरा नहीं है। जेनरिक के उपयोग से परहेज करके कंपाइलर कास्ट में जोड़ने से बच सकता है।

+7

मुझे नहीं लगता कि इसमें कुछ भी नहीं है "सीपीयू टिक" के साथ। – assylias

+0

@assylias कास्टिंग मुक्त नहीं है। लेकिन यह एक बेहतर इंटरफेस विनिर्देश प्रदान करने का लाभ भी है। –

+4

कास्टिंग शायद मुफ़्त नहीं है लेकिन मुझे नहीं लगता कि कक्षा के डिजाइन के साथ इसका कोई संबंध नहीं है। – assylias

3

मैं कारण अनुमान लगा रहा है कि containsAll (और contains, remove, removeAll) की तुलना के लिए Object#equals का उपयोग करता है।

आप कल्पना कर सकते हैं कि Object#equalsE में विधि ओवरराइड हो सकती है जो true को कुछ असंबंधित वर्गों की वस्तुओं के लिए वापस कर सकती है। यह नहीं कि यह एक अच्छा विचार होगा, लेकिन यह एक वैध कार्यान्वयन हो सकता है।

+1

यह कभी-कभी एक अच्छा विचार है। उदाहरण के लिए, 'java.util.List' की आवश्यकता है कि अलग-अलग सूची वर्गों के लिए भी, समान सामग्री वाले सूचियों के लिए'equals() 'वापसी सही हो। – newacct

1

कारण तरीकों add और contains के लिए के रूप में ही है।

add, संग्रह के सामान्य प्रकार का एक तर्क लेता है क्योंकि केवल इस तरह की वस्तुओं संग्रह में जोड़ा जा सकता है। संग्रह में जेनेरिक का उपयोग करने का यह पूरा बिंदु है।

contains (साथ ही remove और Map.get जैसे संग्रह ढांचे में अन्य विधियां) किसी ऑब्जेक्ट को पैरामीटर के रूप में स्वीकार करती हैं। कम से कम दो कारण हैं।

सबसे पहले, के रूप में टोबियास ब्रांट ने कहा, कि कर रहे हैं "बराबर" एक पूरी तरह से अलग प्रकार की वस्तुओं के संग्रह में एक वस्तु (के रूप में उनके equals कार्यान्वयन द्वारा परिभाषित) हो सकता है। जहां डी ई का एक सुपर वर्ग है

दूसरा, हर संग्रह Collection<E>Collection<? extends D> के रूप में देखा जा सकता है, या Collection<?> के रूप में भी (जो Collection<? extends Object> के समान है)। यदि आप यह उपहास करते हैं, तो आप add विधि को अब कॉल नहीं कर सकते हैं, क्योंकि यह हस्ताक्षर add(?) जैसा दिखता है और संकलक इसे कॉल करने से मना कर देता है क्योंकि यह कभी भी सुरक्षा सुरक्षा सुनिश्चित नहीं कर सकता है (और यह अच्छा है कि आप add पर कॉल नहीं कर सकते क्योंकि आप कर सकते हैं संग्रह में गलत प्रकार जोड़ें)। हालांकि, यह अभी भी contains पर कॉल करने के लिए उपयोगी हो सकता है और यह हमेशा सुरक्षित टाइप होता है, इसलिए इसकी अनुमति क्यों नहीं दी जानी चाहिए? इसे अनुमति देने के लिए, contains विधि को Object पैरामीटर प्रकार के रूप में रखने की आवश्यकता है, अन्यथा इसे add के समान नहीं कहा जा सकता है।

addAll और containsAll के हस्ताक्षर बस इसी सिद्धांत का पालन करें।

+1

"हालांकि, यह अभी भी कॉल करने के लिए उपयोगी हो सकता है और यह हमेशा सुरक्षित टाइप होता है" लेकिन यह फिर से है क्योंकि 'ऑब्जेक्ट.equals()' सभी प्रकार लेता है। यदि 'ऑब्जेक्ट.equals() 'सभी प्रकार नहीं लेता है, तो यह हमेशा सुरक्षित प्रकार नहीं होगा। – newacct

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