2016-05-04 2 views
11

मैं जेनरिक के साथ प्रयोग करना और पाया कि, मेरे आश्चर्य करने के लिए, निम्न कोड को संकलित किया गया था:सर प्रकारों का उपयोग करते समय जावा टाइपएफ़ क्यों नहीं है?

class A {} 
class B extends A {} 

class Generic<T> { 
    private T instance; 
    public Generic(T instance) { 
     this.instance = instance; 
    } 
    public T get(){ return instance; } 
} 

public class Main { 
    public static void main(String[] args) { 
     fArray(new B[1], new Generic<A>(new A())); // <-- No error here 
    } 

    public static <T> void fArray(T[] a, Generic<? extends T> b) { 
     a[0] = b.get(); 
    } 
} 

मैं TB लिए अनुमान लगाया जा की उम्मीद करेंगे। AB का विस्तार नहीं करता है। तो संकलक इसके बारे में शिकायत क्यों नहीं करता?

TObject से अनुमानित प्रतीत होता है, क्योंकि मैं Generic<Object> भी पास कर सकता हूं।

इसके अलावा, जब वास्तव में कोड चल रहा है, यह a[0] = b.get(); लाइन पर एक ArrayStoreException फेंकता है।

मैं किसी भी कच्चे जेनेरिक प्रकार का उपयोग नहीं कर रहा हूं। मुझे लगता है कि इस अपवाद को संकलन समय त्रुटि, या कम से कम एक चेतावनी से बचा जा सकता था, अगर T वास्तव में B होने का अनुमान लगाया गया था।


जब List<...> बराबर के साथ आगे की जांच:

public static void main(String[] args) { 
    fList(new ArrayList<B>(), new Generic<A>(new A())); // <-- Error, as expected 
} 

public static <T> void fList(List<T> a, Generic<? extends T> b) { 
    a.add(b.get()); 
} 

यह उत्पादन है और इसे गलती:

The method fList(List<T>, Generic<? extends T>) in the type Main is not applicable for the arguments (ArrayList<B>, Generic<A>) 

अधिक सामान्य मामले करता है:

public static <T> void fList(List<? extends T> a, Generic<? extends T> b) { 
    a.add(b.get()); // <-- Error here 
} 

संकलक सही ढंग से पहचानता है कि पहले ? दूसरे ? की तुलना में विरासत पदानुक्रम को आगे बढ़ा सकता है।

उदा। यदि पहले ?B थे और दूसरा ?A था तो यह सुरक्षित प्रकार नहीं है।


तो पहला उदाहरण एक समान संकलक त्रुटि का उत्पादन क्यों नहीं करता है? क्या यह सिर्फ एक निरीक्षण है? या क्या कोई तकनीकी सीमा है?

एक ही रास्ता मैं एक त्रुटि उत्पादन कर सकता है स्पष्ट रूप से एक प्रकार प्रदान कर रहा है:

Main.<B>fArray(new B[1], new Generic<A>(new A())); // <-- Not applicable 

मैं वास्तव में अपने खुद के अनुसंधान के माध्यम से कुछ भी नहीं मिला, this article के अलावा 2005 से (जेनरिक से पहले) , जो सरणी covariance के खतरों के बारे में बात करता है।

ऐरे कॉन्वर्सिस एक स्पष्टीकरण की ओर इशारा करते हुए प्रतीत होता है, लेकिन मैं एक के बारे में नहीं सोच सकता।


वर्तमान JDK है 1.8.0.0_91

+0

मुझे आश्चर्य है कि क्या आप जेनेरिक में जावा के प्रकार के मिटा के खिलाफ उछाल रहे हैं? बस एक विचार, मेरे पास करीब एटीएम देखने के लिए समय नहीं है। – Ukko

उत्तर

4

इस उदाहरण पर विचार T -> A अनुमान रनटाइम पर पूरी तरह से उचित है।

और वहाँ संकलक बताने के लिए कि आपके सरणी संदर्भ विधि के कार्यान्वयन में लिए इस्तेमाल किया जाएगा के लिए कोई रास्ता नहीं है।

+0

@ जोर्नवीर्नी हाँ, मैंने इसे ओवरड किया लेकिन आपको सामान्य विचार मिलता है। कंपाइलर को 'टी -> बी' चुनने का कोई कारण नहीं है जब 'टी -> ए 'सभी मानदंडों को पूरा करता है। – biziclop

+0

हां, यह बहुत अच्छा है। लेकिन मुद्दा यह है कि आप यह कहकर अतिरिक्त प्रकार की सुरक्षा जोड़ना चाहते हैं कि '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' जैसे आप 'ए 'ए = नया ए() करते हैं; एक ए = = ए '' '' 'ऑब्जेक्ट ए = नया ए(); ए 2 = (ए) ए; '' 'कभी-कभी दूसरा ठीक होता है (जब कास्टिंग होता है), लेकिन यह सुनिश्चित करने के लिए कि हम पहले तरीके का उपयोग करते हैं, क्योंकि इसमें टाइप सुरक्षा है। –

+0

@JornVernee मेला पर्याप्त है। अभी के बारे में कैसे? :) – biziclop

2

I would expect T to be inferred to B. A does not extend B. So why doesn't the compiler complain about it?

TB होने के लिए पता नहीं लगाया जाता है, यह A होने के लिए मान लिया जाता है।चूंकि BA बढ़ाता है, B[]A[] का उप प्रकार है, और इसलिए विधि कॉल सही है।

जेनरिक के विपरीत, सरणी का तत्व प्रकार रनटाइम पर उपलब्ध है (वे संशोधित हैं)। तो जब आप

a[0] = b.get(); 

क्रम पर्यावरण जानता है कि a वास्तव में एक B सरणी है और एक A धारण नहीं कर सकता करने की कोशिश।

समस्या यहां है कि जावा गतिशील रूप प्रदान कर रहा है है। जावा के पहले संस्करण के बाद से Arrays हैं, जबकि जेनेरिक केवल जावा 1.5 में जोड़े गए थे। आम तौर पर, ओरेकल नए जावा संस्करणों को पिछड़ा संगत बनाने की कोशिश करता है, और इसलिए पुराने संस्करणों में बनाई गई त्रुटियां (उदाहरण के लिए सरणी कॉन्वर्सिस) को नए संस्करणों में सही नहीं किया जाता है।

class A {} 
class B extends A {} 

class Generic<T> { 
    private T instance; 
    public Generic(T instance) { 
     this.instance = instance; 
    } 
    public T get(){ return instance; } 
} 

public class Main { 
    public static void main(String[] args) { 
     fArray(new B[1], new Generic<A>(new A())); // <-- No error here 
    } 

    public static <T> void fArray(T[] a, Generic<? extends T> b) { 
     List<T> list = new ArrayList<>(); 
     list.add(a[0]); 
     list.add(b.get()); 
     System.out.println(list); 
    } 
} 

आप देख सकते हैं, प्रकार पैरामीटर अनुमान लगाने के लिए इस्तेमाल किया हस्ताक्षर समान हैं, केवल बात अलग है कि fArray() केवल सरणी तत्वों के बजाय पढ़ता है उन्हें लेखन, बनाने का है:

+0

मैं जैसा कहा: _ "' '' T''' को '' 'Object''', के बाद से मैं पारित कर सकते हैं एक' '' जेनेरिक '' 'रूप में अच्छी तरह का अनुमान लगाया जा रहा है।" _ लेकिन आप मुझे बता सकते हैं _why_ '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' या यदि आप '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' ' –

+0

'T' क्योंकि' जेनेरिक '' की जेनेरिक 'एक उप-प्रकार नहीं है,' Object' के रूप में पता नहीं लगाया जाता है, क्योंकि तब आप 'जेनेरिक ' अपने पद्धति के लिए एक पारित करने में सक्षम नहीं होगा। बेशक, यदि आप वास्तव में 'सामान्य ' के बजाय 'जेनेरिक ' पास करते हैं, तो 'टी' को 'ऑब्जेक्ट' होने का अनुमान लगाया जाता है। – Hoopje

+0

तो '' 'T''' है' '' Object''' तो '' 'जेनेरिक ' '' '' 'संतुष्ट जेनेरिक ' ''। यह कॉल '' 'मुख्य द्वारा आगे सिद्ध किया जाता है। fArray (नया बी [1], नया जेनेरिक (नया ए())); '' ', जो त्रुटियों के बिना संकलित करता है। –

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