2013-02-01 13 views
11

निम्नलिखित नमूने में, Foo.test() में पहली कॉल के लिए जेनेरिक तर्कों का अनुमान लगाने में सक्षम क्यों है, लेकिन दूसरे में ऐसा करने में सक्षम नहीं है? मैं जावा 6.तर्कों के रूप में उपयोग किए जाने वाले कार्यों के लिए जेनेक सामान्य प्रकार के तर्कों का अनुमान क्यों नहीं लगा सकते हैं?

public class Nonsense { 
    public static class Bar { 
     private static void func(Foo<String> arg) { } 
    } 

    public static class Foo<T> { 

     public static <T> Foo<T> create() { 
      return new Foo<T>(); 
     } 

     private static void test() { 
      Foo<String> foo2 = Foo.create(); // compiles 
      Bar.func(Foo.create());   // won't compile 
      Bar.func(Foo.<String>create()); // fixes the prev line 
     } 
    } 
} 

(संकलन त्रुटि है विधि समारोह (Nonsense.Foo) प्रकार Nonsense.Bar में तर्क (Nonsense.Foo) लिए लागू नहीं है) का उपयोग कर रहा हूँ।

नोट: मैं समझता हूं कि संकलक त्रुटि परीक्षण() में तीसरी पंक्ति द्वारा तय की जा सकती है - मुझे इस बात की उत्सुकता है कि क्या एक विशिष्ट सीमा है जो संकलक को प्रकार का अनुमान लगाने में सक्षम होने से रोकती है। यह मेरे लिए दिखाई देता है कि यहां इसके लिए पर्याप्त संदर्भ है।

+4

मुझे यकीन नहीं है कि आप क्या जवाब देते हैं, इसके अलावा "यह पर्याप्त स्मार्ट नहीं है।" –

+0

@ लुइस - यह कल्पना की जा सकती है कि पर्याप्त स्मार्ट होना संभव नहीं है, लेकिन मुझे पता नहीं चला कि क्यों, अभी तक। – bacar

+0

@bacar: शायद यह काफी स्मार्ट होना संभव है, यह सिर्फ नहीं है। –

उत्तर

14

विशिष्ट जानकारी के अनुसार जावा 7 के रूप में होता है, विधि अधिभार संकल्प विधि आप बुला रहे हैं से किसी भी लक्ष्य प्रकार की जानकारी से पहले आगे बढ़ने के लिए है func की घोषणा में प्रकार परिवर्तनीय T का अनुमान लगाने के लिए ध्यान में रखा जा सकता है। यह मूर्खतापूर्ण लगता है, क्योंकि हम सभी देख सकते हैं इस मामले में वहाँ एक और केवल एक विधि func नामित, तथापि, यह JLS द्वारा अनिवार्य है और इस प्रकार 7.

संकलन आय के रूप में जावा से javac के व्यवहार है कि: सबसे पहले, संकलक देखता है कि यह func नामक क्लास बार की एक स्थिर विधि को कॉल संकलित कर रहा है। ओवरलोड रिज़ॉल्यूशन करने के लिए, यह पता लगाना चाहिए कि विधि के साथ किस पैरामीटर को बुलाया जा रहा है। यह एक मामूली मामला होने के बावजूद, इसे अभी भी ऐसा करना चाहिए, और जब तक यह नहीं किया जाता है, तो इसकी सहायता के लिए उपलब्ध विधि के औपचारिक मानकों के बारे में कोई जानकारी नहीं है। वास्तविक पैरामीटर में एक तर्क होता है, Foo.create() पर कॉल जिसे Foo<T> लौटने के रूप में घोषित किया जाता है। फिर, लक्ष्य विधि से कोई मानदंड नहीं होने पर, यह केवल यह अनुमान लगा सकता है कि वापसी प्रकार Foo<T> का क्षरण है जो Foo<Object> है, और ऐसा करता है।

विधि अधिभार रिज़ॉल्यूशन तब विफल रहता है, क्योंकि func के ओवरलोड्स में से कोई भी Foo<Object> के वास्तविक पैरामीटर के साथ संगत नहीं है, और उस त्रुटि को एक त्रुटि उत्सर्जित की जाती है।

यह निश्चित रूप से बेहद दुर्भाग्यपूर्ण है क्योंकि हम सभी यह देख सकते हैं कि यदि जानकारी कॉल साइट के लिए विधि कॉल के लक्ष्य से सीधे दूसरी दिशा में बहती है, तो प्रकार को आसानी से अनुमानित किया जा सकता है और वहां होगा कोई ग़लती नहीं। और वास्तव में जावा 8 में कंपाइलर बस ऐसा कर सकता है, और करता है। जैसा कि एक और जवाब में कहा गया है, यह समृद्ध प्रकार का संदर्भ लैम्बडास के लिए बहुत उपयोगी है जो जावा 8 में जोड़ा जा रहा है, और जावा एपीआई के विस्तार के लिए जो लैम्बडास का लाभ उठाने के लिए किए जा रहे हैं।

आप पिछले लिंक से Java 8 with JSR 335 lambdas का प्री-रिलीज़ बिल्ड डाउनलोड कर सकते हैं।यह किसी भी चेतावनी या त्रुटियों के बिना प्रश्न में कोड संकलित करता है।

3

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

जावा 8 में आपका उदाहरण संकलित करता है। लैम्ब्डा अभिव्यक्ति उपयोग के मामलों के कारण जावा टीम अधिक अनुमान लगाने के लिए प्रेरित है। यह एक आसान काम नहीं है।

जावा 7 के लिए जावा भाषा विशिष्टता 40 पृष्ठों सिर्फ विधि मंगलाचरण अभिव्यक्ति (अनुभाग 15,12)

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

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