2012-12-20 19 views
9

मुझे यह एक जोशुआ ब्लोच द्वारा दी गई Google I/O गूढ़ व्यक्ति से मिली है। यहाँ कोडजावा जेनरिक प्रकार विधि पैरामीटर का मिटा

public class Glommer<T> { 
     String glom(Collection<?> obj){ 
     String result = ""; 
     for(Object o : obj){ 
       result += o; 
     } 
     return result; 
     } 

     int glom(List<Integer> ints){ 
      int result = 0; 
      for(int i : ints){ 
       result += i; 
      } 
      return result; 
     } 

     public static void main(String args[]){ 
      List<String> strings = Arrays.asList("1", "2", "3"); 
      System.out.println(new Glommer().glom(strings)); 
     } 

इस मुख्य विधि एक अपवाद फेंकता है क्योंकि new Glommer एक कच्चे प्रकार है और इसलिए Glommer में सभी जेनरिक मिटा दिया जाता है, इसलिए यह String glom(Collection<?> obj) बजाय int glom(List<Integer> ints) बुला समाप्त होता है।

मेरा प्रश्न है, भले ही मैं बुलाया glom() रूप new Glommer<Integer>().glom(strings) यह int glom(List<Integer> ints) विधि नहीं बुलाना चाहिए विलोपन टाइप करने के लिए कारण के बाद से, इस विधि को प्रभावी ढंग से int glom(List ints) है और strings प्रकार List नहीं Collection की है, है?

उत्तर

7

बुलाया गया तरीका संकलन समय पर परिभाषित किया गया है, रनटाइम पर नहीं।

यदि आप अपने कन्स्ट्रक्टर कॉल में पैरामीटर जोड़ते हैं, तो संकलक के पास पर्याप्त जानकारी होगी कि उसे पहली विधि को कॉल करना होगा। अन्यथा, ऐसा लगता है जैसे जेनेरिक मौजूद नहीं थे। दोनों स्थितियों में, कॉल की गई विधि हमेशा रनटाइम पर ही रहेगी।

public class Test { 

    private static void test(Object object) { 
     System.out.println("Object method"); 
    } 

    private static void test(Integer integer) { 
     System.out.println("Integer method"); 
    } 

    public static void main(String[] args) { 
     Object object = Integer.valueOf(0); 
     test(object); 
    } 

} 

परिणाम है::

Object method 

आप अपने विधि के लिए एक पूर्णांक गुजरती हैं, लेकिन सभी संकलक संकलन में जानता है कि

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

+0

मैं कहूंगा कि कंपाइलर निष्पादित करने के तरीके के हस्ताक्षर को निर्धारित करता है, लेकिन निष्पादित करने की विधि को वास्तविक ऑब्जेक्ट प्रकार का उपयोग करके रनटाइम पर चुना जाता है। – tcb

+0

@tcb मैंने एक उदाहरण जोड़ा, इसे आजमाएं। – WilQu

+0

मैं समझता हूं कि आप क्या कहना चाहते हैं और इस उदाहरण में आप सही हैं, लेकिन मेरे शब्द एक सामान्य मामले के बारे में थे जहां आप ओवरराइड विधियों के साथ व्युत्पन्न कक्षा प्राप्त कर सकते हैं। – tcb

0

ऐसा इसलिए है क्योंकि जब new Glommer() को जेनिक्स के बिना Generic<Type>() कहा जाता है, तो सभी प्रकार के मिलान कक्षा से हटा दिए जाते हैं।

स्ट्रिंग वैरिएबल List है, यदि उसके पास कोई सामान्य <Type> नहीं है तो यह glom(List ints) से मेल खाएगा। प्रकार की जांच बाद में नहीं की जाती है।

जब हम new Glommer<AnyType> बनाते हैं तो सभी प्रकार शेष होते हैं, इसलिए जब हम strings वैरिएबल पास करते हैं तो यह जांच प्रकार टाइप करता है। कंपाइलर अब जांच कर सकता है कि यह List<Integer> है, जो ऐसा नहीं है, इसलिए यह glom(Collection<?> obj) विधि में पारित हो जाता है।

उम्मीद है कि यह मदद करता है, अगर आपको आवश्यकता हो तो कृपया कोई स्पष्टीकरण मांगें!

+0

कंपाइलर में बदल गया। –

1

आप Raw Types के बारे में अधिक पढ़ सकते हैं यह समझने में पूरी तरह से

असल में, कच्चे प्रकार के कर रहे हैं विरासत कोड का उपयोग कर के लिए, एक कच्चे कक्षा में लगभग कुछ भी कच्चे ही हो जाएगा, इस मामले में उन 2 तरीकों।

इसलिए, जब कच्चे है वहाँ एक तरीका है कि एक List और इसलिए इसकी बुलाया Collection के लिए एक हो जाता है है List एक है, अगर इसकी कच्चे नहीं, विधियों नहीं भी कच्चे हैं और क्योंकि यह है यह Collection एक कॉल करेंगे अतिरिक्त जानकारी