2012-04-12 12 views
5

मैं सी ++ टेम्पलेट्स और सी # जेनेरिक के बारे में एक चर्चा पढ़ रहा था, और वे जावा के प्रकार-मिटाए गए जेनेरिक से अलग कैसे हैं। मैंने एक बयान पढ़ा जो कहा कि जावा अभी भी रनटाइम पर कास्टिंग का उपयोग करता है, उदाहरण के लिए संग्रह से निपटने पर। यदि यह सच है, तो मुझे इसके बारे में पता नहीं था!जावा जेनेरिक रनटाइम पर कास्टिंग का उपयोग कब करते हैं?

ArrayList<SomeClass> list = new ArrayList<SomeClass>(); 
... 
SomeClass object = list.get(0); 

मेरा प्रश्न है:

कहते हैं कि मैं इस तरह के रूप कोड करते हैं। क्या यह प्रभावी रूप से

ArrayList list = new ArrayList(); 
... 
SomeClass object = (SomeClass) list.get(0); 

यदि संकलित है, तो क्यों? मैंने सोचा कि तथ्य यह है कि सूची ArrayList<SomeClass> गारंटी है, संकलित समय और रन टाइम पर, केवल कुछ क्लास ArrayList के अंदर संग्रहीत किया जाएगा? या क्या आप कभी भी ArrayList<OtherClass> को ArrayList<SomeClass> में बदलने के लिए असुरक्षित प्रकार-कास्टिंग कर सकते हैं?

क्या ऐसे कई मौके हैं जहां जावा जेनेरिक में रनटाइम प्रकार कास्टिंग किया जाता है?

अंत में, यदि रन टाइम पर कास्टिंग वास्तव में उपयोग किया जाता है, तो क्या ऐसे अवसर होते हैं जब जेआईटी रन टाइम कास्ट चेक को बढ़ा सकता है?

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

+2

आपके पास बहुत सारे प्रश्न हैं। लेकिन इसका उत्तर नीचे आता है: संकलन समय त्रुटि – ControlAltDel

+0

की जांच में सुधार करने के लिए जावा जेनरिकों को रखा गया था यह ओरेकल (सूर्य) द्वारा प्रदान की गई विभिन्न जेनरिक जानकारी और ट्यूटोरियल द्वारा बहुत अधिक कवर किया गया है। पिछड़े संगतता को बनाए रखने के लिए जेनरिक को संकलन-समय सुविधा के रूप में बोल्ड किया गया था। http://java.sun.com/j2se/1.5/pdf/generics-tutorial.pdf –

+0

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

उत्तर

5

में संकलित यहाँ एक छोटी कार्यक्रम मैंने लिखा है:

public class Test<T> { 

    public T contents; 

    public Test(T item) { 
    contents = item; 
    } 

    public static void main(String[] args) { 

    Test<String> t = new Test<String>("hello"); 
    System.out.println(t.contents); 

    } 

} 

javac साथ यह संकलन की कोशिश करो, और फिर javap -verbose साथ बाईटकोड को देखो।मैंने कुछ रोचक लाइनों का चयन किया है:

public java.lang.Object contents; 

यह टेस्ट कन्स्ट्रक्टर की परिभाषा से ठीक पहले चालू होना चाहिए। उदाहरण कोड में यह टाइप टी का था, अब यह एक ऑब्जेक्ट है। यह मिटाना है।

अब, मुख्य विधि को देख:

public static void main(java.lang.String[]); 
Code: 
    Stack=3, Locals=2, Args_size=1 
    0: new #3; //class Test 
    3: dup 
    4: ldC#4; //String hello 
    6: invokespecial #5; //Method "<init>":(Ljava/lang/Object;)V 
    9: astore_1 
    10: getstatic #6; //Field java/lang/System.out:Ljava/io/PrintStream; 
    13: aload_1 
    14: getfield #2; //Field contents:Ljava/lang/Object; 
    17: checkcast #7; //class java/lang/String 
    20: invokevirtual #8; //Method java/io/PrintStream.println:(Ljava/lang/String;)V 
    23: return 

तो हम लाइन 17 पर checkcast आदेश देख सकते हैं, बस println से पहले - यह वह जगह है जहाँ जावा मिट सामान्य प्रकार के Object से डाले - String

+0

धन्यवाद। अच्छे खर्च! –

5

आपकी धारणा सही है।

ArrayList<X> good = new ArrayList<X>(); 
ArrayList q = x; 
ArrayList<Y> evil = (ArrayList<Y>)q; //Doesn't throw due to type erasure 
evil.add(new Y()); //this will actually succeed 
X boom = good.get(0); 

ArrayList<Y> करने के लिए ArrayList से डाली (हमेशा) एक अनियंत्रित डाली चेतावनी दे देंगे, लेकिन (यह भी हमेशा) पर सफल होगा:

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

+0

हुह? यह क्या है? – ControlAltDel

+0

@ उपयोगकर्ता 12 9 14 9 2: क्या? – SLaks

+0

आप केवल 5 वर्णों के साथ एक टिप्पणी कैसे छोड़ते हैं - यह मुझे कम से कम 15 करता है! – ControlAltDel

1

याद रखें कि रनटाइम पर, ArrayList<String>ArrayList जैसा ही है और अंतर्निहित Object[] के साथ लागू किया गया है। जेआईटी अक्सर जानवरों को दूर करने के लिए पर्याप्त स्मार्ट होता है, हां, लेकिन चूंकि जेनेरिक रनटाइम पर मिटा दिए जाते हैं, इसलिए केस्ट आवश्यक हैं।

0

जावा अपने संस्करणों के बीच संगतता बनाए रखने के लिए बहुत अच्छा काम कर रहा है जिसका अर्थ है कि जावा 5 + वाक्यविन्यास को 1.4 संगत वर्गों में संकलित किया जा सकता है। मुझे लगता है कि कारण है कि ArrayList रन समय पर गारंटी देता है कि केवल कुछ क्लास ArrayList के अंदर संग्रहीत किया जाएगा।

और यह देखने के लिए कि आपका जेनेरिक कोड वास्तव में किस प्रकार संकलित है, कृपया उत्कृष्ट JAD टूल का उपयोग करें।

आपका कोड वास्तव में SomeClass object = (SomeClass) list.get(0);

1

मैंने सोचा था कि तथ्य यह है कि सूची, प्रकार ArrayList गारंटी की है में समय संकलन और समय चलाने के लिए, यह है कि केवल SomeClass ArrayList के अंदर संग्रहित किया जाएगा? या क्या आप कभी भी ArrayList को ArrayList में बदलने के लिए असुरक्षित प्रकार-कास्टिंग कर सकते हैं?

हां, प्रकार की जानकारी रन-टाइम पर छोड़ दी जाती है।

इसका मतलब है कि आप समझ नहीं सकते हैं कि आपके पास ArrayList<String> या ArrayList<Long> प्रकार का ऑब्जेक्ट है। जेवीएम सामान्य वर्गों के उदाहरणों के लिए वास्तविक प्रकार के तर्कों को नहीं जानता है, इसलिए आपके पास उस रन-टाइम चेक नहीं हैं (और जब आप उस डेटा का उपभोग करेंगे तो आपको केवल त्रुटियां दिखाई देगी)।

इस कोड को मान्य है:

public void enqueueItem(ArrayList<Integer> list, Integer item) { 
    List listAlias = list; 
    listAlias.add(x.toString()); 
} 

यह रन-टाइम में एक समस्या नहीं है, प्रकार की जाँच अभी भी वहाँ है किसी भी मुद्दे से आप को बचाने के लिए और आप नए कोड के साथ पुराने कोड Interop कर सकते हैं। यहां तक ​​कि .NET वातावरण में भी आपका वही व्यवहार है (IList<T>IList से निकला है)।

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

public ArrayList getCollection() { 
    return new ArrayList<Integer>(); 
} 

public void doStuff() { 
    ArrayList<String> list = getCollection(); 
    list.add("text"); 
} 

वहाँ अन्य अवसरों जहां पर-क्रम प्रकार कास्टिंग जावा जेनरिक में किया जाता है कर रहे हैं?

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

अंत में, यदि रन टाइम पर कास्टिंग वास्तव में उपयोग किया जाता है, तो क्या ऐसे अवसर होते हैं जब जेआईटी रन टाइम कास्ट चेक को बढ़ा सकता है?

मुझे लगता है कि नहीं, यह हमेशा एक डाली करता है लेकिन यह एक बहुत ही कार्यान्वयन विस्तार वैसे भी यह उपवर्गों के लिए प्रकार तर्क पटरियों इसलिए यदि आप एक सामान्य वर्ग से अपने खुद के वर्ग निकाले जाते हैं तो आप से बचाया जा जाएगा यह अंक

यदि हां, तो क्यों?

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

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