2009-08-06 27 views
8
public void wahey(List<Object> list) {} 

wahey(new LinkedList<Number>()); 

विधि को कॉल टाइप-चेक नहीं करेगा। इस प्रकार मैं भी पैरामीटर कास्ट नहीं कर सकते हैं:सूची <Number> क्यों उप-प्रकार की सूची <Object> नहीं है?

wahey((List<Object>) new LinkedList<Number>()); 

अपना शोध से, मैं इकट्ठे हुए हैं कि टाइप-सुरक्षा है इस की अनुमति नहीं दे के लिए कारण। हम ऊपर करने के लिए अनुमति दी गई थी, तो हम निम्नलिखित हो सकता है:

List<Double> ld; 
wahey(ld); 

विधि wahey के अंदर, हम इनपुट सूची में कुछ तार जोड़ सकता है (के रूप में पैरामीटर List<Object> संदर्भ बनाए रखता है)। अब, विधि कॉल के बाद, ld एक प्रकार को संदर्भित करता है जिसमें List<Double> है, लेकिन वास्तविक सूची में कुछ स्ट्रिंग ऑब्जेक्ट्स हैं!

जेनिक्स के बिना जावा काम सामान्य तरीके से अलग लगता है। उदाहरण के लिए:

Object o; 
Double d; 
String s; 

o = s; 
d = (Double) o; 

क्या हम यहाँ क्या कर रहे हैं अनिवार्य रूप से एक ही बात है, सिवाय इस संकलन समय जांचों में कामयाब होगा और केवल रन-टाइम में असफल। सूची के साथ संस्करण संकलित नहीं होगा।

इससे मुझे विश्वास होता है कि यह जेनेरिक पर प्रकार के प्रतिबंधों के संबंध में एक डिजाइन निर्णय है। मैं इस फैसले पर कुछ टिप्पणियां लेने की उम्मीद कर रहा था?

+1

संबंधित (सटीक डुप्लिकेट नहीं, हालांकि सही उत्तर मूल रूप से वही है): http: // stackoverflow।कॉम/प्रश्न/2512 9 8/क्यों-कुछ-कुछ-विशेष-टी-नहीं-समकक्ष-से-कुछ-जावा-जेनेरिक-प्रकार – Kip

+3

कला की अवधि ** covariance ** है - मैं इसका उल्लेख करता हूं क्योंकि यह इसका कारण है स्टैक ओवरफ़्लो (यदि आप देखना चाहते हैं कि मुझे इसके बारे में क्या कहना है - सी # के संदर्भ में, लेकिन यह जावा पर भी लागू होता है - [covariance उपयोगकर्ता के लिए खोज: 95810], उदाहरण के लिए)। –

+0

'वही' (सूची ) (सूची ) की एक डबल कास्ट) नई ArrayList ()) 'संकलित करेगा, हालांकि इसकी अनुशंसा नहीं की जाती है। – Robin479

उत्तर

9

आप "जेनरिक के बिना" उदाहरण में क्या कर रहे हैं उदाहरण एक कलाकार है, जो यह स्पष्ट करता है कि आप कुछ प्रकार-असुरक्षित कर रहे हैं। जेनरिक के साथ बराबर होगा:

Object o; 
List<Double> d; 
String s; 

o = s; 
d.add((Double) o); 

कौन सा उसी तरह बर्ताव करता है (compiles, लेकिन कार्यावधि में विफल रहता है)। जिस व्यवहार के बारे में आप पूछ रहे हैं उसे अनुमति न देने का कारण यह है क्योंकि यह निहित प्रकार-असुरक्षित कार्रवाइयों की अनुमति देगा, जो कोड में नोटिस करना बहुत कठिन है। उदाहरण के लिए:

public void Foo(List<Object> list, Object obj) { 
    list.add(obj); 
} 

यह पूरी तरह से ठीक है और टाइप सुरक्षित लग रहा है जब तक आप इसे इस तरह कहते हैं: क्योंकि तुम फोन करने वाले जरूरी नहीं पता है कि के रूप में

List<Double> list_d; 
String s; 

Foo(list_d, s); 

कौन सा भी प्रकार सुरक्षित लग रहा है, फू अपने पैरामीटर के साथ करने जा रहा है।

तो इस मामले में आपके पास कोड के दो प्रतीत होता है-सुरक्षित बिट्स हैं, जो एक साथ टाइप-असुरक्षित होते हैं। यह बुरा है, क्योंकि यह छिपी हुई है और इसलिए इसे टालना मुश्किल है और डीबग करना कठिन है।

+0

आह, मैं देखता हूं। आपका बहुत बहुत धन्यवाद। :) –

8

अगर यह था पर विचार करें ...

List<Integer> nums = new ArrayList<Integer>(); 
List<Object> objs = nums 
objs.add("Oh no!"); 
int x = nums.get(0); //throws ClassCastException 

आप सूची में माता पिता के प्रकार के कुछ भी जोड़ने की है, जो नहीं हो सकता है कि यह पूर्व में घोषित किया गया था, के रूप में के रूप में ऊपर उदाहरण दर्शाता है जो सक्षम हो जाएगा , सभी प्रकार की समस्याओं का कारण बनता है। इस प्रकार, इसकी अनुमति नहीं है।

+0

यह सही है, लेकिन सवाल इंगित करता है कि वह पहले से ही इसे समझता है, और यह जानना चाहता है कि इस व्यवहार को प्रतिबंधित करने के लिए निर्णय क्यों किया गया था, जबकि अभी भी अन्य प्रकार के प्रकार-असुरक्षित व्यवहार की अनुमति है। –

+0

मैं इस उदाहरण को पहले ही समझ चुका हूं। मैंने प्रश्न में इस परिदृश्य को समझाने की कोशिश की (जैसा कि टायलर ने कहा था), लेकिन टिप्पणी के लिए धन्यवाद। –

+1

इस प्रकार असुरक्षित व्यवहार वास्तव में * है * सरणी के साथ अनुमति है। निम्नलिखित संकलित बस ठीक है लेकिन रनटाइम त्रुटि उत्पन्न करता है: 'ऑब्जेक्ट [] arr = नया इंटीजर [2]; एआर [0] = "ओह नहीं!"; ' – Kip

4

जेनिक्स कैसे काम करते हैं, वे एक दूसरे के उपप्रकार नहीं हैं। क्या आप चाहते हैं इस तरह से अपनी समारोह की घोषणा करने के लिए है:

public void wahey(List<?> list) {} 

तो यह कुछ भी की एक सूची है कि वस्तु का विस्तार स्वीकार करेंगे।आप यह भी कर सकते हैं:

public void wahey(List<? extends Number> list) {} 

इससे आपको संख्या के उप-वर्ग की सूची में शामिल होने दिया जाएगा।

मैं आपको मॉरीस Naftalin & फिलिप वाडलर द्वारा "जावा जेनरिक और संग्रह" की एक प्रतिलिपि लेने की सलाह दूंगा।

+0

+1, इस तरह जेनेरिक काम करता है। ** डीओ ** जावा जेनरिक और संग्रह की एक प्रति चुनें। बहुत बढ़िया किताब! – WolfmanDragon

+0

यह मेरा सवाल नहीं था। मुझे पता है ये जेनेरिक के साथ उप-टाइपिंग के नियम हैं। –

3

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

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

+0

अच्छी व्याख्या, धन्यवाद। –

1

"What we are doing here is essentially the same thing, except this will pass compile-time checks and only fail at run-time. The version with Lists won't compile."

आप क्या देख रहे हैं सही समझ में आता है।

java.sun.com

Generics provides a way for you to communicate the type of a collection to the compiler, so that it can be checked. Once the compiler knows the element type of the collection, the compiler can check that you have used the collection consistently and can insert the correct casts on values being taken out of the collection.

0

जावा में, List<S>से जब ST की एक उप-प्रकार है नहींList<T> की एक उप-प्रकार है। यह नियम प्रकार सुरक्षा प्रदान करता है।

मान लें कि हम List<String> को List<Object> का उपप्रकार होने की अनुमति देते हैं। निम्नलिखित उदाहरण पर विचार करें:

public void foo(List<Object> objects) { 
    objects.add(new Integer(42)); 
} 

List<String> strings = new ArrayList<String>(); 
strings.add("my string"); 
foo(strings); // this is not allow in java 
// now strings has a string and an integer! 
// what would happen if we do the following...?? 
String myString = strings.get(1); 

तो, यह मजबूर करना सुरक्षा की सुरक्षा प्रदान करता है लेकिन इसमें भी कमी है, यह कम लचीला है। निम्न उदाहरण पर विचार करें:

class MyCollection<T> { 
    public void addAll(Collection<T> otherCollection) { 
     ... 
    } 
} 

यहाँ आप T के का एक संग्रह है, तो आप एक और संग्रह से सभी आइटम जोड़ना चाहते हैं। T के उप प्रकार के लिए आप Collection<S> के साथ इस विधि को कॉल नहीं कर सकते हैं। आदर्श रूप में, यह ठीक है क्योंकि आप केवल अपने संग्रह में तत्व जोड़ रहे हैं, आप पैरामीटर संग्रह को संशोधित नहीं कर रहे हैं।

इसे ठीक करने के लिए, जावा उन्हें "वाइल्डकार्ड" कहता है। वाइल्डकार्ड कॉन्वर्सिस/contravariance प्रदान करने का एक तरीका है। ,

class MyCollection<T> { 
    // Now we allow all types S that are a subtype of T 
    public void addAll(Collection<? extends T> otherCollection) { 
     ... 

     otherCollection.add(new S()); // ERROR! not allowed (Here S is a subtype of T) 
    } 
} 

अब वाइल्डकार्ड के साथ हम प्रकार टी में सहप्रसरण अनुमति देते हैं और हम (संग्रह में एक आइटम जोड़ने उदाहरण के लिए) कार्य है कि सुरक्षित टाइप नहीं कर रहे हैं ब्लॉक: अब निम्न का उपयोग कर वाइल्डकार्ड पर विचार करें। इस तरह हम लचीलापन और प्रकार की सुरक्षा प्राप्त करते हैं।

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