2013-08-03 7 views
13
public class Test { 
    public static class Nested<T> { 
     public T val; 
     Nested(T val) { this.val = val; } 
    } 
    public static void main(String[] args) { 
     Nested<Integer> a = new Nested<Integer>(5); 
     Nested<Integer> b = new Nested<Integer>(2); 
     Integer diff = a.val - b.val; 
    } 
} 

उपरोक्त कोड ठीक काम करता है। हालांकि, अगर मैं नेस्ट के लिए एक विधि जोड़ें:जावा के प्रकार का मिटा क्यों नहीं टूटता है?

T diff(Nested<T> other) { return this.val - other.val; } 

मैं एक संकलन त्रुटि मिलती है:

operator - cannot be applied to T,T 

यह मेरे लिए समझ में आता है। टी का प्रकार रनटाइम पर मिटा दिया जाता है, इसलिए जावा ऑपरेटर को लागू नहीं कर सकता है जिसे केवल इंटीजर जैसे कुछ वर्गों के लिए परिभाषित किया जाता है। लेकिन a.val - b.val क्यों काम करता है?

संपादित करें:

बहुत सारे अच्छे उत्तरों। सबको धन्यवाद। इसका अर्थ, अगर मैं सही ढंग से समझता हूं, तो यह है कि संकलक a.val - b.val में इंटीजर को जोड़ सकता है क्योंकि यह जानता है कि a और bNested<Integer> के रूप में तत्काल थे। हालांकि, this.val - other.val एक सामान्य फ़ंक्शन परिभाषा के शरीर के अंदर होता है (जहां टी अभी भी कुछ भी हो सकता है), कंपाइलर उन कैस्ट को नहीं जोड़ सकता जो "-" काम करने के लिए आवश्यक होंगे। इससे एक और दिलचस्प सवाल होता है, अर्थात्, यदि जावा कंपाइलर इनलाइनिंग करने में सक्षम था, तो क्या काम करने के लिए अलग-अलग कार्य के लिए यह संभव होगा?

+1

'एवल' का प्रकार संकलन-समय पर पहले मामले में 'इंटेगर' होने के लिए जाना जाता है, लेकिन दूसरे मामले में केवल 'टी' होता है। दूसरे मामले में, विचार करें कि क्या होता है यदि कोई अन्य मॉड्यूल कुछ वर्ग 'Foo' के लिए' test.Nested 'को तत्काल करता है। – nneonneo

+0

विशेष रूप से, कंपाइलर 'a.val' और 'b.val' अभिव्यक्तियों के सामने एक' (पूर्णांक) 'कास्ट डालता है। यही जेनेरिक है। –

उत्तर

9

दोनों के बीच का अंतर यह है कि क्या आप एक सामान्य विधि के अंदर हैं या आप इसके बाहर हैं।

आपको यह बिल्कुल सही मिला कि विधि T के अंदर Integer नहीं है, इसलिए ऑपरेटर शून्य - लागू नहीं किया जा सकता है। हालांकि, जब आप जेनेरिक विधि के बाहर main() में हैं, तो संकलक जानता है कि आपने Nested को Integer के साथ तुरंत चालू कर दिया है, इसलिए यह ऑपरेटर को कैसे लागू करें, यह बहुत अच्छी तरह से जानता है। यद्यपि जेनेरिक के कार्यान्वयन ने Nested<T> के लिए कोड का उत्पादन करने के लिए इस प्रकार को मिटा दिया है, संकलक a और bNested<T> के संदर्भ में नहीं सोचता है: इसमें उचित कास्ट डालने, परिणामों को अनबॉक्स करने और शून्य को लागू करने के लिए पर्याप्त ज्ञान है - ऑपरेटर।

1

a.val - b.val काम करता है क्योंकि यह संकलक द्वारा मान्य है, रनटाइम में नहीं। कंपाइलर "देखता है" कि आप < इंटीजर > का उपयोग कर रहे हैं और यह संकलित और रन चलाता है, रनटाइम में एरर के साथ भी कोई समस्या नहीं है क्योंकि संकलक पहले से ही मान्य है।

1

क्योंकि विधि कॉल रनटाइम पर है और a.val - b.val संकलन समय पर चेक किया गया है।

  • पहले मामले में, संकलक जानता प्रकार Integer और - आपरेशन पूर्णांकों के लिए अनुमति दी है है।
  • दूसरे मामले में, T का प्रकार पहले से संकलक को ज्ञात नहीं है, इसलिए यह सुनिश्चित नहीं है कि - ऑपरेशन मान्य है या नहीं। इसलिए संकलक त्रुटि।

मान लें कि हम विधि को diff(Nested<Book> other) के रूप में उपयोग करते हैं, इसलिए कोई पुस्तक किसी अन्य से घटाई जा सकती है।

8

आपको एक संकलन-समय त्रुटि मिल रही है, रनटाइम नहीं।

public static void main(String[] args) { 
    Nested<Integer> a = new Nested<Integer>(5); 
    Nested<Integer> b = new Nested<Integer>(2); 
    Integer diff = a.val - b.val; 
} 

यहाँ, संकलक कि दोनों TInteger हैं जानता है। आपने अभी <Integer> घोषित किया है।

T diff(Nested<T> other) { return this.val - other.val; } 

यहां, कंपाइलर T के बारे में निश्चित नहीं है। यह कुछ भी हो सकता है। और, संख्यात्मक केवल ऑपरेटर - किसी भी चीज़ के लिए अनुमति नहीं है।

1

क्योंकि कोड नेस्टेड के भीतर नहीं रहता है, इस प्रकार का नाम ज्ञात है। संकलक स्पष्ट रूप से देख सकता है कि a.val-b.val एक इंटीजर शून्य एक इंटीजर है, जिसे ऑटो-बॉक्स किया जा सकता है। संकलक अनिवार्य रूप से

Integer diff = Integer.valueOf(((Integer) a.val).intValue() - ((Integer) b.val).intValue()) 

.intValue और .valueOf कॉल ऑटो मुक्केबाजी और ऑटो unboxing से हैं करने के लिए उसे पुनः लिखता है।

कंपाइलर डालने के लिए टाइप कास्ट सुरक्षित हैं क्योंकि आपने पैरामीटरयुक्त प्रकार नेस्टेड का उपयोग किया था।

सच है, तकनीकी रूप से, कैलेंडर ऑब्जेक्ट की तरह कुछ और हो सकता है, क्योंकि प्रकार रनटाइम पर अज्ञात है। लेकिन यदि आप जेनेरिक का उपयोग कर रहे हैं, तो संकलक विश्वास करता है कि आप इसे रोकने के लिए कुछ भी नहीं कर रहे हैं। इसलिए, यदि एक .val या b.val इंटीजर के अलावा कुछ भी था, तो क्लासकास्ट अपवाद रनटाइम पर फेंक दिया जाएगा।

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