2010-11-22 19 views
7

क्या कोई समझा सकता है कि दूसरी कक्षा संकलित क्यों नहीं होती है?क्या एरर का रिटर्न टाइप हिस्सा है?

1 javac और JDK 6 का उपयोग ठीक संकलित है कि उदाहरण के लिए एक छोटी सी परिवर्तन (ग्रहण इस कोड को शिकायत)

public class SameSignatureMethods { 
    public <T extends String> Boolean test() 
    { 
     return true; 
    } 

    public <T extends Character> Double test() 
    { 
     return 1d; 
    } 
} 

2, और संकलन निम्नलिखित त्रुटि के साथ विफल:

name clash: <T>test() and <T>test() have the same erasure 

केवल परिवर्तन विधि पर वापसी प्रकार है:

public class SameSignatureMethods { 
    public <T extends String> Boolean test() 
    { 
     return true; 
    } 

    public <T extends Character> Boolean test() { 
     return true; 
    } 
} 

यह बताता है कि कैसे firs के लिए मुख्य विधि टी वर्ग दिखेगा:

public static void main(String[] args) { 
    SameSignatureMethods m = new SameSignatureMethods(); 
    System.out.println("m.<Character>test()=" + m.<Character>test()); 
    System.out.println("m.<String>test()=" + m.<String>test()); 
} 
+0

हम्म, दिलचस्प एक। आपने किस कंपाइलर का उपयोग किया था? जेडीके या कुछ आईडीई-बिल्टिन? पहले व्यक्ति ग्रहण 3.6 एसआर 1 (जो सही है) में संकलित नहीं करता है। – BalusC

+0

जावा संस्करण "1.6.0_18" जावा (टीएम) एसई रनटाइम पर्यावरण (1.6.0_18-बी07 का निर्माण) जावा हॉटस्पॉट (टीएम) क्लाइंट वीएम (बिल्ड 16.0-बी 13, मिश्रित मोड) – Yuriy

+0

@ बाल्लूसी रिटर्न प्रकार नहीं है विधि हस्ताक्षर का हिस्सा है, है ना? त्रुटि संदेश हालांकि अजीब है। – extraneon

उत्तर

4

तो, जेडीके कंपाइलर पहले संस्करण को संकलित करता है लेकिन दूसरा नहीं, जबकि ग्रहण कंपाइलर दो संस्करणों में से किसी एक को संकलित नहीं करता है।

जावा बाइट कोड के दृष्टिकोण से, पहले संस्करण में दो अलग-अलग विधियां (टाइप एरर के बाद), अर्थात् public java.lang.Boolean test() और public java.lang.Double test() है, जो पूरी तरह से मान्य है। जब आप जेनेरिक तरीकों को ओवरराइड करते हैं तो जेडीके कंपाइलर और ग्रहण कंपाइलर कभी-कभी ऐसे तरीकों को उत्पन्न करते हैं, लेकिन फिर उन्हें सिंथेटिक ब्रिज विधियों के रूप में चिह्नित किया जाता है।

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

Exception in thread "main" java.lang.ClassFormatError: Duplicate method name&signature in class file SameSignatureMethods 
    at java.lang.ClassLoader.defineClass1(Native Method) 
    at java.lang.ClassLoader.defineClassCond(Unknown Source) 
    at java.lang.ClassLoader.defineClass(Unknown Source) 
    at java.security.SecureClassLoader.defineClass(Unknown Source) 
    at java.net.URLClassLoader.defineClass(Unknown Source) 
    at java.net.URLClassLoader.access$000(Unknown Source) 
    at java.net.URLClassLoader$1.run(Unknown Source) 
    at java.security.AccessController.doPrivileged(Native Method) 
    at java.net.URLClassLoader.findClass(Unknown Source) 
    at java.lang.ClassLoader.loadClass(Unknown Source) 
    at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source) 
    at java.lang.ClassLoader.loadClass(Unknown Source) 
Could not find the main class: SameSignatureMethods. Program will exit. 

वर्ग मैं इस तरह दिखता है के साथ शुरू कर दिया। मैं स्ट्रिंग और डबल का इस्तेमाल किया क्योंकि वे एक ही नाम की लंबाई है:

public class SameSignatureMethods { 
    public <T extends String> String test() { 
     return null; 
    } 

    public <T extends Double> Double test() { 
     return null; 
    } 

    public static void main(String[] args) { 
     System.out.println(new SameSignatureMethods().<Double>test()); 
    } 
} 

फिर, एक हेक्स संपादक का उपयोग कर, मैं कच्चे के साथ एक वर्ग फ़ाइल के दो स्थानों पर public <T extends String> Double test() को पहली विधि के हस्ताक्षर बदल गया है, हस्ताक्षर ()Ljava/lang/Double;, जेनेरिक हस्ताक्षर <T:Ljava/lang/String;>()Ljava/lang/Double; के साथ एक।

+0

क्या आप उस पर थोड़ा विस्तार कर सकते हैं?मैंने सोचा कि वापसी का प्रकार हस्ताक्षर का हिस्सा नहीं है – Yuriy

+1

रिटर्न प्रकार किसी वर्ग को संकलित करते समय हस्ताक्षर का हिस्सा नहीं है, जैसा कि आप जानते हैं, एक आमंत्रण के लिए जो वापसी मूल्य को अनदेखा करता है, संकलक चुन नहीं सकता था। लेकिन बाइट कोड में, वापसी प्रकार हस्ताक्षर का हिस्सा है। आप दो वर्गों को संकलित करके इसका परीक्षण कर सकते हैं, एक दूसरे की विधि को कॉल कर सकते हैं, और फिर केवल कॉल किए गए विधि के रिटर्न प्रकार को बदल सकते हैं। उस वर्ग को संकलित करें लेकिन कॉलिंग क्लास नहीं, और प्रोग्राम चलाएं। आपको NoSuchMethodError मिलता है। –

+0

यदि मैं बाइट कोड सत्यापनकर्ता अक्षम (अनुशंसित नहीं है) के साथ JVM प्रारंभ करता हूं, तो प्रोग्राम 'null' चलाता है और प्रिंट करता है, क्योंकि JVM समान हस्ताक्षर वाले दो तरीकों में से एक को आमंत्रित करता है। यदि मैं इसके बजाय 'स्ट्रिंग' वापस करने के लिए दोनों विधियों के हस्ताक्षर बदलता हूं, तो प्रोग्राम NoSuchMethodError के साथ विफल रहता है, क्योंकि दो तरीकों में से कोई भी मुख्य विधि द्वारा अनुरोधित 'डबल' वापसी प्रकार नहीं है। –

1

प्रथम श्रेणी (SameSignatureMethods) में, क्रम वापसी Boolean और Double क्रमश: 2 तरीके। दूसरी कक्षा में दोनों विधियां Boolean लौटती हैं।

<T extends String> विधि परिभाषा के सामने इसका मतलब यह नहीं है कि यह एक रिटर्न प्रकार है।

हो सकता है कि आप इस तरह से कुछ करना चाहता हूँ:

public <T extends String> T test() 
{ 
    return obj;// obj could be a String 
} 

हालांकि, सामान्य प्रकार के क्रम में मिट जाता है, और विधि से ऊपर हो जाएगा

public Object test() 
{ 
    return obj;// obj could be a String 
} 
+1

हां, लेकिन पहले क्यों एक संकलन? – BalusC

+0

दोनों वर्गों में विधियां वास्तविक प्रकार लौटती हैं। जेनिक्स, घोषित होने पर, बिल्कुल उपयोग नहीं किया जाता है। कक्षाओं के बीच एकमात्र अंतर दूसरे तरीकों में केवल एक ही नाम और तर्क नहीं होता है, बल्कि समान रिटर्न प्रकार भी होते हैं - और यह कि एक त्रुटि फेंकने के लिए कंपाइलर बनाता है। यदि आप जेनेरिक को हटाते हैं, तो वे दोनों संकलित नहीं होंगे, लेकिन पहले एक वास्तव में ठीक से संकलित करता है। – Yuriy

+0

प्रथम श्रेणी संकलित नहीं होती है: 'डुप्लिकेट विधि परीक्षण() प्रकार SameSignatureMethods' में। शायद आपने किया सही ढंग से कोड की प्रतिलिपि न लें। जैसा कि मैंने पहले ही अपने उत्तर में कहा है: एक सामान्य प्रकार की परिभाषा _ का मतलब यह नहीं है कि यह एक रिटर्न प्रकार है ._ आप बाद में विधि की सामग्री में या पैरा में इसका उपयोग कर सकते हैं मीटर, लेकिन रिटर्न प्रकार अभी भी आपके मामले में 'बूलियन' है। –

2

लगता है कि आपने भ्रमित करने के लिए कामयाब रहे अपने संकलक बहुत:

  • रिटर्न प्रकार हस्ताक्षर का हिस्सा नहीं है। कंपाइलर यह कहने के लिए रिटर्न प्रकार का उपयोग नहीं कर सकता कि कौन सी विधि कहलाई जा रही है।

  • आपके उदाहरण में विधि हस्ताक्षर में क्रोधित जेनेरिक सामान वैसे भी रिटर्न प्रकार को प्रभावित नहीं करता है।

  • यह भी कह रहा है कि <T extends String> कोई मतलब नहीं है, आप अंतिम प्रकार का विस्तार नहीं कर सकते हैं। (हम्म, यह सिर्फ एक चेतावनी है, यह संकलन रोक नहीं करता है)

आप क्यों द्वितीय श्रेणी संकलन नहीं करता है, मुझे आश्चर्य है कि क्यों प्रथम श्रेणी संकलित करता है। जैसा कि, पहली कक्षा संकलन के बावजूद संकलित है। पॉइंट ब्रैकेट सामान को बाहर निकालने के परिणामस्वरूप 'डुप्लिकेट विधि' त्रुटि होती है जिसे परवाह किए बिना दिखाना चाहिए। एक कंपाइलर बग होना चाहिए।

+0

में संकलित नहीं है, यह वास्तव में मेरे लिए पूरी तरह सैद्धांतिक प्रश्न है। यह मानक है क्योंकि यह 1.6.0_18 कंपाइलर प्राप्त करता है, और फिर - तथ्य यह है कि प्रथम श्रेणी संकलन मुझे सही समझ में आता है - यह जावा स्पेक के अनुसार जाता है। दूसरा संकलन नहीं कर रहा है - जो कि मैं संकुचित नहीं करता – Yuriy

+1

हाँ # 1 संकलक बग के कारण संकलित करता है - देखें: http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6182950 - यह अब संकलित नहीं है जेडीके 7 (या ग्रहण 3.6+ में, जैसा कि उन्होंने इसे भी सही किया) –

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