2010-08-10 11 views
9

में विफल रहता है मेरे पास निम्न परीक्षण वर्ग है जो किसी विधि को ओवरलोड करने के लिए जेनरिक का उपयोग करता है। जब यह जावैक के साथ संकलित होता है और ग्रहण हेलीओस में संकलन करने में विफल रहता है तो यह काम करता है। मेरा जावा संस्करण 1.6.0_21 है।जावा जेनेरिक कोड जेवाक के साथ संकलित करता है, ग्रहण हेलीओस

मेरे द्वारा पढ़े गए सभी लेख इंगित करते हैं कि ग्रहण सही है और यह कोड काम नहीं करना चाहिए। हालांकि जब जावैक और रन के साथ संकलित किया जाता है, तो सही विधि का चयन किया जाता है।

यह कैसे संभव है?

धन्यवाद!

import java.util.ArrayList; 

public class Test { 
    public static void main (String [] args) { 
     Test t = new Test(); 
     ArrayList<String> ss = new ArrayList<String>(); 
     ss.add("hello"); 
     ss.add("world"); 
     ArrayList<Integer> is = new ArrayList<Integer>(); 
     is.add(1); 
     is.add(2); 
     System.out.println(t.getFirst(ss)); 
     System.out.println(t.getFirst(is)); 
    } 
    public String getFirst (ArrayList<String> ss) { 
     return ss.get(0); 
    } 
    public Integer getFirst (ArrayList<Integer> ss) { 
     return ss.get(0); 
    } 
} 
+4

यदि यह वास्तविक उपयोग केस है, तो मैं केवल एक विधि की सिफारिश करता हूं 'सार्वजनिक ए getFirst (ArrayList एसएस) {वापसी ss.get (0); } '... अगर यह चित्रण प्रयोजनों के लिए अभी विकसित हुआ है, तो –

+1

क्या आप लेख उद्धृत कर सकते हैं? – trashgod

उत्तर

2

यदि जावा में इसमें एक बग था तो यह संभव होगा। जावाक सिर्फ सॉफ्टवेयर है और सॉफ्टवेयर के किसी भी अन्य टुकड़े के रूप में बग के लिए उत्तरदायी है।

प्लस, जावा भाषा स्पेक बहुत जटिल है और स्थानों में थोड़ा अस्पष्ट है, इसलिए यह ग्रहण लड़कों और जावैक लोगों के बीच व्याख्या में अंतर में भी अंतर हो सकता है।

मैं ग्रहण समर्थन चैनलों पर यह पूछकर शुरू करूंगा। वे आम तौर पर इन चीजों को चुनने और यह समझाने में बहुत अच्छे होते हैं कि वे क्यों सोचते हैं कि वे सही हैं या अन्यथा यह स्वीकार करते हुए कि वे गलत हैं।

रिकॉर्ड के लिए, मुझे लगता है कि एक्लिप्स भी यहां है।

+0

में एक और तरीका ग्रहण गलत है के रूप में है। यह पूरी तरह से कानूनी जावा है। – erickson

+0

मेह। मैं ऐतिहासिक औसत के आधार पर पूरी तरह से अनुमान लगा रहा था। अन्य लोगों के विश्लेषण को देखते हुए, मुझे संदेह है कि आप सही हैं। किसी भी तरह से, ग्रहण लोगों के साथ इसे बढ़ाने का रास्ता आगे है। – dty

2

क्या आप सुनिश्चित हैं कि एक्लिप्स जावा 1.6 का उपयोग करने के लिए भी सेट है?

+2

ब्याज से, आपको ऐसा क्यों लगता है कि यह प्रासंगिक है? ग्रहण कम से कम 1.5 पर सेट है या अन्यथा यह संकलित नहीं होगा। क्या आपको लगता है कि 1.5 और 1.6 में भाषा अर्थशास्त्र के बीच कुछ महत्वपूर्ण अंतर है? – dty

+0

मैं बस यह सुनिश्चित करना चाहता था कि यह 1.4 पर सेट न हो। मैं ग्रहण का उपयोग नहीं करता, लेकिन मुझे पता है कि आईडीई के पास आमतौर पर एक जावा संस्करण सेटिंग आपके सिस्टम से स्वतंत्र होती है। जहां तक ​​1.5-1.6 मतभेद हैं, मुझे किसी भी महत्वपूर्ण लोगों के बारे में पता नहीं है। – Jeffrey

+0

यदि यह 1.4 पर सेट किया गया था तो यह जेनेरिक के कारण बिल्कुल संकलित नहीं होता। – dty

0

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

+2

यहां भाषा के साथ थोड़ा ढीला। स्पष्ट होने के लिए, जावैक संकलक है कि सूर्य (ओरेकल) प्रकाशित करता है। और ग्रहण तीसरे पक्ष के कंपाइलर का उपयोग नहीं करता है - यह अपने स्वयं के कंपाइलर कार्यान्वयन का उपयोग करता है। – dty

3

एक्लिप्स हेलीओस में मेरे लिए काम करता है। विधि चयन संकलन समय पर होता है, और संकलक के पास ऐसा करने के लिए पर्याप्त जानकारी होती है।

4

यह कोड सही है, जैसा कि JLS 15.12.2.5 Choosing the Most Specific Method में वर्णित है।

इसके अलावा, इंटरफ़ेस करने के लिए कोडिंग पर विचार करें:

List<String> ss = new ArrayList<String>(); 
List<Integer> is = new ArrayList<Integer>(); 
// etc. 

@McDowell नोटों के रूप में, संशोधित विधि हस्ताक्षर वर्ग फ़ाइल में दिखाई देते हैं:

$ javap build/classes/Test 
Compiled from "Test.java" 
public class Test extends java.lang.Object{ 
    public Test(); 
    public static void main(java.lang.String[]); 
    public java.lang.String getFirst(java.util.ArrayList); 
    public java.lang.Integer getFirst(java.util.ArrayList); 
} 

ध्यान दें कि यह @ Meriton के अवलोकन का खंडन नहीं करता कक्षा फ़ाइल के बारे में। उदाहरण के लिए, इस टुकड़ा

Method[] methods = Test.class.getDeclaredMethods(); 
for (Method m : methods) { 
    System.out.println(Arrays.toString(m.getGenericParameterTypes())); 
} 

के उत्पादन main() की औपचारिक पैरामीटर, साथ ही दो सामान्य प्रकार पैरामीटर पता चलता है:

[class [Ljava.lang.String;] 
[java.util.ArrayList<java.lang.String>] 
[java.util.ArrayList<java.lang.Integer>] 
+1

प्रकार विलोपन के बाद, विधि हस्ताक्षर बन 'सार्वजनिक स्ट्रिंग getFirst (ArrayList)' और 'सार्वजनिक पूर्णांक getFirst (ArrayList)'। – McDowell

+1

कोई मैकडॉवेल नहीं, विधि हस्ताक्षर मिटा नहीं गए हैं। – meriton

+0

@meriton: @McDowell: IIUC, आप दोनों corect हैं: हस्ताक्षर, सामान्य प्रकार पैरामीटर संरक्षित कर रहे हैं _and_ मिट रहे हैं, जैसा कि ऊपर का सुझाव दिया। – trashgod

0

एक बिंदु को ध्यान में रखना है कि सभी है (?, निश्चित रूप से कुछ उदाहरण के लिए नेटबीन संपादक यह करता है) स्थिर कोड विश्लेषण उपकरण विधि हस्ताक्षर के हिस्से के रूप में वापसी प्रकार या संशोधक (निजी/सार्वजनिक आदि) पर विचार नहीं करते हैं।

यदि ऐसा है, तो टाइप एरर की सहायता से getFirst विधियों को getFirst(java.util.ArrayList) हस्ताक्षर मिलेगा और इसलिए एक नाम टकराव ट्रिगर करेगा ...

+0

जेनिक्स * बाइटकोड * (जावा वर्चुअल मशीन का निर्देश सेट) में मिटा दिया गया है। विधि हस्ताक्षर निर्देश सेट का हिस्सा नहीं हैं; वे स्रोत कोड में निर्दिष्ट क्लास फ़ाइल में लिखे गए हैं। अधिक जानकारी के लिए, मेरा जवाब देखें। – meriton

6

Java Language Specification, section 8.4.2 लिखते हैं:

यह एक संकलन समय एक कक्षा में ओवरराइड-बराबर हस्ताक्षर (नीचे वर्णित) के साथ दो तरीकों घोषित करने के लिए त्रुटि है।

दो विधि हस्ताक्षर एम 1 और एम 2 ओवरराइड-समकक्ष आईएफएफ हैं या तो एम 1 एम 2 या एम 2 का सबनिग्नेचर एम 1 का सबनिग्नेचर है। यदि या तो

  • एम 2 एम 1 के समान हस्ताक्षर है, या

  • एम 1 के हस्ताक्षर एक ही है

    एक विधि एम 1 के हस्ताक्षर एक विधि एम 2 के हस्ताक्षर के एक subsignature है एम 2 के हस्ताक्षर के क्षरण के रूप में।

जाहिर है, तरीकों बराबर हावी नहीं कर रहे हैं, के बाद से ArrayList<String>ArrayList (ArrayList<Integer> का विलोपन) नहीं है।

तो विधियों की घोषणा कानूनी है। साथ ही, विधि आमंत्रण अभिव्यक्ति मान्य है, क्योंकि वहां सबसे विशिष्ट विधि है, क्योंकि तर्क प्रकारों से मेल खाने वाली केवल एक विधि है।

संपादित करें: यिशई सही ढंग से इंगित करता है कि इस मामले में एक और प्रतिबंध बारीकी से स्कर्ट किया गया है। Java Language Specification, section 8.4.8.3 लिखते हैं:

यह एक संकलन समय त्रुटि है अगर एक प्रकार घोषणा टी एक सदस्य विधि एम 1 है और एक विधि एम 2 टी में घोषित या टी इस तरह के के महाप्रकार मौजूद है जब निम्नलिखित शर्तें पूरी होल्ड:

  • एम 1 और एम 2 का एक ही नाम है।
  • m2 टी
  • से सुलभ है एम 1 का हस्ताक्षर m2 के हस्ताक्षर का एक उपनिवेश (§8.4.2) नहीं है।
  • एम 1 या कुछ विधि एम 1 ओवरराइड (प्रत्यक्ष या परोक्ष रूप से) एम 2 या कुछ विधि एम 2 ओवरराइड (प्रत्यक्ष या अप्रत्यक्ष रूप से) के समान मिटा है।

परिशिष्ट: ersure, और

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

इसके बारे में सोचो: प्रकार पैरामीटर पूरी तरह से वर्ग फ़ाइलों से मिटा रहे थे, तो कैसे कर सकता है अपनी पसंद प्रदर्शन के आईडीई में कोड पूरा होने कि ArrayList.add(E) प्रकार E की एक पैरामीटर लेता है, और नहीं Object (= E का विलोपन) अगर आपके पास जेडीके स्रोत कोड संलग्न नहीं था? और संकलक कैसे संकलन त्रुटि को फेंकने के बारे में जानता है जब विधि तर्क का स्थिर प्रकार E का उप प्रकार नहीं था?

कोड, के रूप में यह ऊपर निर्दिष्ट किया जाता है संकलन नहीं करना चाहिए:

+3

मुझे लगता है कि मामला इस से काफी करीब है। विचार करें: यदि आप ऑब्जेक्ट में दोनों विधियों के रिटर्न प्रकार बदलते हैं, तो कोड अब संकलित नहीं होगा। जेएलएस यह नहीं कहता है कि ओवरराइड-समतुल्यता निर्धारित करने के लिए रिटर्न प्रकार एक विधि हस्ताक्षर पर एक विशिष्ट विशेषता हो सकती है। मैं अंततः सहमत हूं कि सूर्य संकलक सही है, लेकिन यह एक बहुत करीबी कॉल है। – Yishai

+0

अच्छा बिंदु, मैंने प्रासंगिक खंड को शामिल करने के लिए संपादित किया है। नियम यह है कि समानता को ओवरराइड करने के बारे में नहीं है (जहां वापसी के प्रकार को कोई फर्क नहीं पड़ता), लेकिन प्रकृति में अधिक सामान्य है। – meriton

1

कुछ शोध के बाद, मैं इस सवाल का जवाब है। ArrayList<String> और ArrayList<Integer>, रनटाइम पर अभी भी ArrayList है। लेकिन आपका कोड काम नहीं कर रहा है क्योंकि लौटने वाला प्रकार। यदि आप दोनों विधियों के लिए समान वापसी प्रकार सेट करते हैं, तो javac संकलित नहीं करेगा ...

मैंने पढ़ा है कि इस त्रुटि के बारे में जावा 1.6 में एक बग है (जो पहले से जावा 1.7 में तय है)। सब कुछ लौटने के प्रकार के बारे में है ... तो, आपको अपने तरीकों के हस्ताक्षर को बदलने की आवश्यकता होगी।

bug 6182950 in Oracle's Bug Database नहीं है।