2013-04-08 9 views
25

मैं जावा सामान्य सुविधा का अध्ययन कर रहा हूँ और मुझे यकीन है कि कैसे निम्नलिखित main विधि में तीसरी लाइन को समझाने के लिए नहीं कर रहा हूँ:लागू जावा जेनेरिक तरीके

public class Example4 { 
    public static void main(final String[] args) { 
     System.out.println(Util.<String>compare("a", "b")); 
     System.out.println(Util.<String>compare(new String(""), new Long(1))); 
     System.out.println(Util.compare(new String(""), new Long(1))); 
    } 
} 

class Util { 
    public static <T> boolean compare(T t1, T t2) { 
     return t1.equals(t2); 
    } 
} 

पहली पंक्ति, संकलित चलाता है, और रिटर्न (उम्मीद के रूप में) false

दूसरी पंक्ति अपेक्षा के अनुसार संकलित नहीं होती है, क्योंकि मैं स्पष्ट रूप से String और Long मिश्रण कर रहा हूं।

तीसरी पंक्ति संकलित, चलाती है, और झूठी वापसी करती है लेकिन मुझे यह समझने की ज़रूरत नहीं है कि यह कैसे काम करता है: क्या संकलक/JVM पैरामीटर प्रकार TObject के रूप में तत्काल करता है? (साथ ही, इस घोषित प्रकार के T रनटाइम प्राप्त करने का कोई तरीका होगा?)

धन्यवाद।

उत्तर

9

उत्तर @Telthien और @newacct 'उत्तरों से परे लगता है। अंतर्निहित टाइपिंग साथ

System.out.println(Util.compare(new String(""), new Long(1))); 

: मैं करने के लिए खुद के लिए बीच का अंतर "देख" उत्सुक था: स्पष्ट रूप से लेखन के साथ

System.out.println(Util.<String>compare("a", "b")); 

, और।

मैंने इन दो पिछली लाइनों पर विविधताओं का उपयोग करके कई प्रयोग किए। इन प्रयोगों से पता चलता है कि, anonymous/local class trick का उपयोग करने से कम, संकलक संकलन के दौरान प्रकारों की जांच करता है लेकिन जेनरेट बाइटकोड केवल पहली पंक्ति के मामले में Object का संदर्भ देता है।

कोड का निम्नलिखित भाग दिखाता है कि स्पष्टीकरण प्रकार तर्क <String> के मामले में टाइपकास्ट को Object तक सुरक्षित तरीके से निष्पादित किया जा सकता है।

// Method descriptor #15 ([Ljava/lang/String;)V 
    // Stack: 7, Locals: 1 
    public static void main(java.lang.String[] args); 
    0 getstatic java.lang.System.out : java.io.PrintStream [16] 
    3 new ca.polymtl.ptidej.generics.java.Util44 [22] 
    6 dup 
    7 invokespecial ca.polymtl.ptidej.generics.java.Util44() [24] 
    10 ldc <String "a"> [25] 
    12 ldc <String "b"> [27] 
    14 invokevirtual ca.polymtl.ptidej.generics.java.Util44.compare(java.lang.Object, java.lang.Object) : boolean [29] 
    17 invokevirtual java.io.PrintStream.println(boolean) : void [33] 
    20 getstatic java.lang.System.out : java.io.PrintStream [16] 
    23 new ca.polymtl.ptidej.generics.java.Util44 [22] 
    26 dup 
    27 invokespecial ca.polymtl.ptidej.generics.java.Util44() [24] 
    30 new java.lang.String [39] 
    33 dup 
    34 ldc <String ""> [41] 
    36 invokespecial java.lang.String(java.lang.String) [43] 
    39 new java.lang.Long [46] 
    42 dup 
    43 lconst_1 
    44 invokespecial java.lang.Long(long) [48] 
    47 invokevirtual ca.polymtl.ptidej.generics.java.Util44.compare(java.lang.Object, java.lang.Object) : boolean [29] 
    50 invokevirtual java.io.PrintStream.println(boolean) : void [33] 
    53 return 
     Line numbers: 
     [pc: 0, line: 24] 
     [pc: 20, line: 25] 
     [pc: 53, line: 26] 
     Local variable table: 
     [pc: 0, pc: 54] local: args index: 0 type: java.lang.String[] 

यह वास्तव में अर्थ है कि सभी कॉल्स, Object औपचारिक पैरामीटर प्रकार के रूप में साथ तरीकों को हमेशा से रहे हैं के रूप में समझाया in another question/answer बनाता है:

public final class Example44 { 
    public static void main(final String[] args) { 
     System.out.println(new Util44<String>().compare("a", "b")); 
     System.out.println(new Util44().compare(new String(""), new Long(1))); 
    } 
} 

final class Util44<T> { 
    private T aT; 
    public boolean compare(T t1, T t2) { 
     System.out.println(this.aT); 
     // I was expecting the second and third assignments to fail 
     // with the first invocation because T is explicitly a String 
     // and then to work with the second invocation because I use 
     // a raw type and the compiler must infer a common type for T. 
     // Actually, all these assignments succeed with both invocation. 
     this.aT = (T) new String("z"); 
     this.aT = (T) new Long(0); 
     this.aT = (T) new Object(); 
     return t1.equals(t2); 
    } 
} 

main विधि के bytecodes की तरह लग रहे। Conlude करने के लिए, संकलक हमेशा जेनरोड्स के लिए Object का उपयोग करता है, इससे कोई फर्क नहीं पड़ता कि कोई स्पष्टीकरण प्रकार तर्क (पहली पंक्ति) या एक निहित प्रकार तर्क है, लेकिन ऑब्जेक्ट्स Object से अलग सामान्य सुपरक्लास हो सकता है।

+1

बस इसे यहां नोट करने के लिए, भले ही आप इसे लिंक करते हों; घटना को "टाइप एरर" कहा जाता है। –

+0

हाँ। असल में, जावा जेनिक्स को पीछे के दृश्य टाइपकास्टिंग के रूप में लागू करता है। उदाहरण के लिए, एक 'ऐरेलिस्ट ' आंतरिक रूप से प्रत्येक तत्व को 'ऑब्जेक्ट' मानता है, लेकिन जब आप इसका उपयोग करते हैं तो इसे स्वचालित रूप से 'स्ट्रिंग' पर वापस भेज देता है। –

20

साझा विरासत प्रकार String और LongObject है।

जब आप इस फ़ंक्शन को Util.<String>compare( के रूप में चलाते हैं तो संकलक दो स्ट्रिंग इनपुट ढूंढने की अपेक्षा करता है, और जब यह नहीं होता है तो त्रुटि देता है। हालांकि, <String> के बिना इसे चलाने के परिणाम निकटतम साझा विरासत प्रकार के उपयोग में परिणाम - इस मामले में, Object

इस प्रकार, जब comparet1 स्वीकार करता है और t2, वे Object के रूप में कास्ट किया गया है, और कोड ठीक चलाता है।

रनटाइम पर वास्तविक प्रकार प्राप्त करने के लिए आप उसी तकनीक का उपयोग करते हैं जिसका उपयोग आप किसी अन्य ऑब्जेक्ट के साथ करेंगे: getClass() जो Object कक्षा से विरासत में मिला है।

+1

इसके अलावा दूसरे भाग (रनटाइम पर घोषित प्रकार के टी प्राप्त करने का तरीका) Google पर "संशोधित जेनरिक" की खोज करें। Gafter.blogspot.com/2006/11/reified-generics-for-java.html – prashant

+0

देखें, getClass() विधि, लागू, t1 पर लागू होती है, स्ट्रिंग वापस कर देगी क्योंकि यह रनटाइम प्रकार है, है ना? –

+0

अधिक शोध करते समय, मैंने इस दिलचस्प ब्लॉग प्रविष्टि पर ठोकर खाई: [सुपर टाइप टोकन] (http://gafter.blogspot.kr/2006/12/super-type-tokens.html)। –

2

हां, ObjectT के लिए एक विकल्प है जो इसे संकलित करने की अनुमति देगा। संकल्पनात्मक रूप से, संकलक T के लिए एक प्रकार का अनुमान लगाता है। यह विशेष रूप से infers इससे कोई फर्क नहीं पड़ता - जब तक कि यह अनुमान लगा सकता है कि कुछ प्रकारT के लिए काम करेगा, तो यह संकलित करता है। इससे कोई फर्क नहीं पड़ता कि अनुमानित प्रकार क्या है, क्योंकि इसका संकलित कोड पर कोई प्रभाव नहीं पड़ता है।

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