2013-07-03 12 views
12

मैंने सोचा है कि जावा एरर संकलन समय में जेनेरिक प्रकारों को मिटा देता है, हालांकि जब मैं इसे स्वयं परीक्षण करता हूं तो मुझे एहसास हुआ कि बाइटकोड में जेनेरिक प्रकारों के बारे में कुछ जानकारी है।जावा टाइप एरर मेरे सामान्य प्रकार मिटा देता है?

मैं 2 वर्गों ने लिखा है::

यहाँ अपने परीक्षण है

import java.util.*; 
public class Test { 
    List integerList; 
} 

और

import java.util.*; 
public class Test { 
    List<Integer> integerList; 
} 

मैं दोनों वर्गों संकलित और सामान्य वर्ग में कहीं मैं इस लाइन को देखा

integerList{blah blah}Ljava/util/List;{blah blah} 
Signature{blah blah}%Ljava/util/List<Ljava/lang/Integer;>;{blah blah}<init> 

नहीं n सामान्य वर्ग:

integerList{blah blah}Ljava/util/List;{blah blah}<init> 

इतनी स्पष्ट रूप से मैं बाईटकोड अंदर सामान्य जानकारी है तो यह विलोपन बात क्या है ??

उत्तर

5

कुछ जेनेरिक प्रकार की जानकारी Signature विशेषताएँ में संग्रहीत की जाती है। JLS 4.8 और 4.6 और JVM spec 4.3.4 देखें। पढ़ें here:

शायद जावा में जेनरिक के बारे में सबसे आम शिकायत है कि वे reified नहीं हैं - वहाँ कार्यावधि में पता करने के लिए एक तरीका है कि एक List<String> एक List<Long> से किसी भी तरह से अलग है नहीं है। मुझे इतना फायदा हुआ है कि मैं सुपर टाइप टोकन पर नील गफ्फर के काम में भागने के लिए आश्चर्यचकित था। यह पता चला है कि जब JVM एक सामान्य वर्ग के उदाहरणों के लिए वास्तविक प्रकार के तर्कों को ट्रैक नहीं करेगा, यह सामान्य वर्गों के उप-वर्गों के लिए वास्तविक प्रकार के तर्कों को ट्रैक करता है। दूसरे शब्दों में, बस एक नई ArrayList() रनटाइम पर, अगर एक वर्ग ArrayList<String> फैली हुई है, तो JVM जानता है कि StringList के प्रकार पैरामीटर के लिए वास्तविक प्रकार तर्क है, जबकि एक नया ArrayList<String>() वास्तव में है।

और Neal Gafter's blog

+2

यह भ्रामक है। मेटाडाटा अभी भी प्रतिबिंब के लिए है। यह ठीक नहीं है। – Antimony

0

मिटा का अर्थ है कि जेनेरिक टाइपिंग बाइट कोड में शामिल नहीं है (जब सूची बनाई जाती है या उपयोग की जाती है)।

आपके द्वारा देखे जाने वाले हस्ताक्षर का उपयोग यह इंगित करने के लिए किया जाता है कि यह क्षेत्र सामान्य है।

1

प्रकार की जानकारी बाईटकोड में यहाँ

integerList = new ArrayList<Integer>(); 

से मिटा दिया जाएगा यह

integerList = new ArrayList(); 

के बराबर होगी और वहाँ integerList से क्रम में पता करने के लिए ऑब्जेक्ट को उसके संकलन समय क्या था कोई संभावना नहीं है प्रकार।

+0

ज़रूर! लेकिन "integerList" की परिभाषा से जो सूची है, JVM प्रकार से –

+1

हां, फ़ील्ड से प्रतिबिंबित करने के साथ पता लगा सकता है, लेकिन यदि आपको ArrayList का उदाहरण मिलता है तो इसके सामान्य प्रकार –

6

यह मिटाने की बात क्या है ??

मिटाना सामान्य से कच्चे प्रकार के लिए एक मानचित्रण है। "वाक्यांश की वजह से" सामान्य वाक्यांश अनिवार्य रूप से व्यर्थ है।मैपिंग का उपयोग करने वाले विनिर्देश महत्वपूर्ण हैं।

दो दिलचस्प उपयोग हैं।

  • इसका उपयोग जेनिक्स का कच्चे प्रकार से उपयोग करने से विधि हस्ताक्षर मैप करने के लिए किया जाता है। यह कच्चे प्रकार के हस्ताक्षर हैं जो ओवरलोडिंग के लिए उपयोग किए जाते हैं। यह "मिटा" के साथ समस्याओं का विशाल बहुमत का कारण बनता है। उदाहरण के लिए, आपके पास एक ही प्रकार में दो विधियां add(List<String>) और add(List<Integer>) नहीं हो सकती हैं। शायद ओवरलोडिंग एक अच्छा विचार नहीं है, और इस सुविधा को जोड़ने की कोई बड़ी इच्छा नहीं है।

  • रनटाइम पर किसी ऑब्जेक्ट के उदाहरण के लिए उपलब्ध प्रकार वह प्रकार है जिसे इसे मिटाया गया था। तो यदि आप कहते हैं, (String) जिसे रनटाइम पर चेक किया जाएगा, लेकिन यदि आप List<String> पर डाले हैं तो केवल उस प्रकार का मिटा (List) चेक किया जाएगा। आपके पास List<String> और List<Integer> प्रकार के वैरिएबल बिल्कुल वैसा ही हो सकते हैं। अभ्यास में, आपको 1.5 और बाद में कास्ट (संदर्भ प्रकारों) का उपयोग नहीं करना चाहिए।

जहां व्यावहारिक, जेनेरिक जानकारी कक्षा फाइलों में रखी जाती है और प्रतिबिंब के माध्यम से उपलब्ध कराई जाती है। तो तुम वर्ग परिभाषाएँ, supertypes, खेतों, तरीकों, कंस्ट्रक्टर्स, आदि

+0

धन्यवाद, आपका उत्तर सहायता नहीं मिलेगा मुझे बहुत –

3

यह एक उदाहरण है जहां शब्दावली का सही उपयोग वास्तव में मायने रखती है पर यह मिल जाएगा: Bytecode अनुदेश जावा वर्चुअल मशीन का सेट है। एक वर्ग फ़ाइल बाईटकोड, लेकिन यह भी जानकारी, जोड़ने (क्षेत्र हस्ताक्षर, विधि हस्ताक्षर, ...) बाईटकोड सत्यापनकर्ता के लिए, डीबगर के लिए, के लिए इस्तेमाल किया होता है ...

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

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

यही है, जावा 1.5 के बाद से हमें एक चर के घोषित प्रकार के बीच अंतर करना चाहिए, और ऑब्जेक्ट के रनटाइम प्रकार को संदर्भित करना चाहिए। पूर्व जेनेरिक का समर्थन करता है, उत्तरार्द्ध नहीं करता है। और हां, इसका मतलब है संकलन समय और रनटाइम प्रकारों के बीच एक-से-एक पत्राचार नहीं है।

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