2015-12-16 10 views
9

मान लीजिए हम निम्नलिखित सामान्य वर्गअगर हम टाइप एरर लागू करते हैं, तो क्यों ओवरटाइल्ड विधियों को रनटाइम पर कॉल किया जाएगा, और क्यों?

public class SomeType<T> { 
    public <E> void test(Collection<E> collection){ 
     System.out.println("1st method"); 

     for (E e : collection){ 
      System.out.println(e); 
     } 
    } 

    public void test(List<Integer> integerList){ 
     System.out.println("2nd method"); 

     for (Integer integer : integerList){ 
      System.out.println(integer); 
     } 
    } 

} 

अब मुख्य विधि के अंदर हम निम्नलिखित कोड का टुकड़ा है

SomeType someType = new SomeType(); 
List<String> list = Arrays.asList("value"); 
someType.test(list); 

someType.test(list) को क्रियान्वित करने का एक परिणाम के रूप में हम के रूप में हमारे कंसोल में "2 विधि" मिल जाएगा अच्छी तरह से java.lang.ClassCastException। जैसा कि मैं समझता हूं, दूसरे test विधि को निष्पादित करने का कारण यह है कि हम SomeType के लिए जेनेरिक का उपयोग नहीं करते हैं। इसलिए, कंपाइलर कक्षा से सभी जेनेरिक जानकारी को तुरंत हटा देता है (यानी <T> और <E> दोनों)। उस दूसरे test विधि के बाद List integerList पैरामीटर के रूप में और निश्चित रूप से List से Collection की तुलना में बेहतर होगा।

अब विचार है कि मुख्य विधि के अंदर हम निम्नलिखित कोड है झलकी

SomeType<?> someType = new SomeType<>(); 
List<String> list = Arrays.asList("value"); 
someType.test(list); 

इस मामले में हम कंसोल में "1 विधि" मिल जाएगा। इसका मतलब है कि पहली टेस्ट विधि निष्पादित की जा रही है। सवाल यह है कि क्यों?

रनटाइम पर मेरी समझ से हमारे पास टाइप एरर की वजह से कोई जेनेरिक जानकारी नहीं है। तो, फिर दूसरा test विधि निष्पादित नहीं की जा सकती है। मेरे लिए दूसरे test विधि (रनटाइम पर) निम्न प्रपत्र public void test(List<Integer> integerList){...} में होना चाहिए?

+3

हमारे पास रनटाइम पर जेनेरिक जानकारी नहीं है, लेकिन विधि विकल्प रनटाइम पर नहीं बनाया गया है। – user2357112

+0

ठीक है, लेकिन विधि विधि कैसे की जाती है? क्या बाइटकोड में कोई विशिष्ट जानकारी है जो जेवीएम को कॉल करने की विधि बताती है? – ruvinbsu

+1

@ruvinbsu क्योंकि संकलक यह तय करता है कि उसे किस विधि को कॉल करना चाहिए, हां। – SomeJavaGuy

उत्तर

3

The JLS is a bit of a rat's nest on this one, लेकिन वहाँ एक अनौपचारिक (उनके शब्दों में, मेरा नहीं) नियम यह है कि आप उपयोग कर सकते है:

[O] ne विधि अन्य की तुलना में अधिक विशिष्ट है, यदि कोई हो मंगलाचरण पहली विधि के द्वारा नियंत्रित किया जा सकता है संकलन-समय त्रुटि के बिना दूसरे को पास किया गया।

तर्क के लिए, के <E> test(Collection<E>) विधि 1, और test(List<Integer>) विधि कॉल 2.

यहाँ में एक नापनेवाला फेंक चलो करते हैं - हम जानते हैं कि इस पूरी क्लास सामान्य है, तो एक प्रकार के बिना इसके बारे में इन्स्टेन्शियशन के कुछ दयालु उत्पादन ... वांछनीय से कम रनटाइम पर चेक टाइप करें।

इस के दूसरे भाग के तथ्य यह है कि List, अगर एक विधि एक List पारित हो जाता है Collection की तुलना में अधिक विशिष्ट है की वजह से है, यह उस प्रकार होना चाहिए कि समायोजित करने के लिए और अधिक आसानी से एक Collection से तलाश करेंगे, चेतावनी के साथ संकलन समय पर चेक किया गया। चूंकि उस कच्चे प्रकार के साथ नहीं है, मेरा मानना ​​है कि यह विशेष चेक छोड़ दिया गया है, और जावा List<Integer>Collection<capture(String)> से अधिक विशिष्ट के रूप में व्यवहार कर रहा है।

आपको JVM के साथ एक बग फाइल करना चाहिए, क्योंकि यह असंगत प्रतीत होता है। या, कम से कम, जिन लोगों ने जेएलएस लिखा है, वे बताते हैं कि यह उनके जीते गणित नोटेशन की तुलना में थोड़ा बेहतर अंग्रेजी में कानूनी क्यों है ...

आगे बढ़ना; अपने दूसरे उदाहरण के साथ, आप हमें वाइल्डकार्ड के रूप में अपना उदाहरण टाइप करने की सौजन्य देते हैं, जो जावा को सही संकलन-समय का दावा करने की अनुमति देता है कि test(Collection<E>)सुरक्षित चुनने के लिए विधि है।

ध्यान दें कि इनमें से कोई भी चेक रनटाइम पर नहीं होता है। यह जावा रन से पहले किए गए सभी निर्णय हैं, क्योंकि संदिग्ध विधि कॉल या असमर्थित पैरामीटर वाले किसी विधि को कॉल संकलित समय त्रुटि में परिणाम देता है।

कहानी का नैतिक: कच्चे प्रकार का उपयोग न करें। वे बुराई हैं। यह प्रकार प्रणाली अजीब तरीकों से व्यवहार करता है, और यह वास्तव में केवल पीछे की संगतता बनाए रखने के लिए है।

+0

अब मैं समझता हूं कि संकलक न केवल गलतियों/त्रुटियों की जांच करता है और बाइटकोड का उत्पादन करता है। यह भविष्य में कॉल करने के लिए किस विधि की कुछ विशिष्ट जानकारी jvm प्रदान करता है। तो, इसका मतलब है कि संकलक वह नहीं है जो सीधे स्रोत कोड का सीधे अनुवाद करता है लेकिन भविष्य के लिए निर्णय भी लेता है। – ruvinbsu

4

लागू विधियों से पहले टाइप एरर (see JSL 15.12.2.3) से मेल खाते हैं। (मिटाना मतलब यह है कि क्रम प्रकार पैरामिट्रीकृत नहीं हैं, लेकिन विधि संकलन समय, जब प्रकार पैरामीटर उपलब्ध थे पर चुना गया था)

list के प्रकार है List<String>, इसलिए:

  • test(Collection<E>)लागू है क्योंकि List<Integer>Collection<E> के साथ संगत, है, जहां EInteger (औपचारिक रूप से, बाधा सूत्र List<Integer> → Collection<E> [E:=Integer]true को कम कर देता है, क्योंकि List<Integer>की एक उप-प्रकार है)।

  • test(List<String>) क्योंकि List<String> साथ List<Integer> (औपचारिक रूप से, बाधा सूत्र List<String>List<Integer>false को कम कर देता है क्योंकि StringInteger के महाप्रकार नहीं है) संगत नहीं है, लागू नहीं है।

विवरण समझायाJSL 18.5.1 में छिपा हुआ है।

test(Collection<E>) के लिए:

θ प्रतिस्थापन हो [ई: = पूर्णांक]

[...]

बाधा सूत्र, सी का एक सेट, निम्न प्रकार से बनाया जाता है: एफ 1, ..., एफएन औपचारिक पैरामीटर प्रकार एम हो, और e1, ..., ek आमंत्रण की वास्तविक तर्क अभिव्यक्ति हो।

इस मामले में, हम F1 = Collection<E> और e1 = List<Integer>

तब है: [बाधा सूत्रों के सेट] शामिल हैं

इस मामले में, हम List<Integer> → Collection<E> [E:=Integer] है (जहां → का अर्थ है कि ई 1 टाइप-वेरिएबल E अनुमानित होने के बाद एफ 1 के साथ संगत है)

के लिए, कोई प्रतिस्थापन नहीं है (क्योंकि कोई अनुमान चर नहीं है) और बाधा केवल List<String>List<Integer> है।

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