2012-03-20 14 views
5

मेरे समस्या किया जा सकता अभिव्यक्त-अप इस स्निपेट द्वारा:जेनेरिक्स और सही प्रकार के लिए कास्टिंग

public interface TheClass<T> { 
    public void theMethod(T obj); 
} 

public class A { 
    private TheClass<?> instance; 

    public A(TheClass<?> instance) { 
     this.instance = instance; 
    } 

    public void doWork(Object target) { 
     instance.theMethod(target); // Won't compile! 

     // However, I know that the target can be passed to the 
     // method safely because its type matches. 
    } 
} 

मेरी कक्षा A अपनी जेनरिक प्रकार अज्ञात साथ TheClass का एक उदाहरण का उपयोग करता है। इसमें Object के रूप में पारित लक्ष्य के साथ एक विधि है जिसमें TheClass इंस्टेंस को किसी भी वर्ग के साथ पैरामीटर किया जा सकता है। हालांकि, संकलक मुझे इस तरह के लक्ष्य को पारित करने की अनुमति नहीं देगा, जो सामान्य है।

इस मुद्दे को रोकने के लिए मुझे क्या करना चाहिए?

एक गंदा समाधान TheClass<? super Object> है, जो ठीक काम करता है लेकिन शब्दार्थ गलत है के रूप में उदाहरण घोषित करने के लिए ...

एक अन्य समाधान मैं पहले इस्तेमाल किया, कच्चे प्रकार के रूप में घोषित करने के लिए उदाहरण सिर्फ TheClass था है, लेकिन यह बुरा है अभ्यास, इसलिए मैं अपनी गलती को सही करना चाहता हूं।

समाधान

public class A { 
    private TheClass<Object> instance; // type enforced here 

    public A(TheClass<?> instance) { 
     this.instance = (TheClass<Object>) instance; // cast works fine 
    } 

    public void doWork(Object target) { 
     instance.theMethod(target); 
    } 
} 
+2

क्यों तुम भी टाइप न करें 'A'? –

+0

+1, एक अच्छे प्रश्न के लिए !! उत्तर के लिए प्रतीक्षारत ... – aProgrammer

+0

ए एक ओपन-सोर्स लाइब्रेरी का हिस्सा है जिसे मैंने बनाया है जिसका उपयोग बहुत से लोगों द्वारा किया जाता है, और टाइपिंग ए का मतलब एक मजबूत एपीआई ब्रेक होगा। मैंने हाल ही में इस मुद्दे की खोज की क्योंकि मैंने "TheClass" उदाहरण के लिए कच्चे प्रकार का उपयोग किया था, क्योंकि मुझे पता नहीं था कि यह बुरी अवधारणा थी। यह ठीक काम करता है, लेकिन बुरा अभ्यास माना जाता है इसलिए मैं इस दुरुपयोग को सही करना चाहता हूं। –

उत्तर

4
public class A { 
    private TheClass<Object> instance; 

    public A(TheClass<Object> instance) { 
     this.instance = instance; 
    } 

    public void do(Object target) { 
     instance.theMethod(target); 
    } 
} 

या

public class A<T> { 
    private TheClass<T> instance; 

    public A(TheClass<T> instance) { 
     this.instance = instance; 
    } 

    public void do(T target) { 
     instance.theMethod(target); 
    } 
} 
+0

+1 के कारण उनका कोड अभी भी पहले जैसा काम करेगा। यह वही है जो मैं टाइप कर रहा था; लेकिन आप पहले वहाँ गए! –

+0

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

1

समाधान भी टाइप करने के लिए A है। वाइल्डकार्ड ? का उपयोग करके आप TheClass की प्रकार की जानकारी खो देते हैं और बाद में इसे पुनर्प्राप्त करने का कोई तरीका नहीं है। वहाँ कुछ बदसूरत हैक्स तुम कर सकते हो रहे हैं, लेकिन अपने सबसे अच्छे शॉट भी टाइप करने के लिए A है:

public interface TheClass<T> { 
    public void theMethod(T obj); 
} 

public class A<T> { 
    private TheClass<T> instance; 

    public A(TheClass<T> instance) { 
     this.instance = instance; 
    } 

    public void doIt(T target) { 
     instance.theMethod(target); 
    } 
} 

यह किसी भी एपीआई या तो तोड़ नहीं होंगे।

+0

+1, धन्यवाद। टाइपिंग ए मेरे लिए एक संभावना नहीं है, क्योंकि यह लाइब्रेरी में बेकार जटिलता जोड़ देगा, लेकिन आप सही हैं, यह केवल कुछ समाधानों में से एक था। –

1

कारण संकलन त्रुटि के लिए कि ? वाइल्डकार्ड जावा में अज्ञात प्रकार को इंगित करता है। आप घोषित कर सकते हैं एक अज्ञात जेनेरिक पैरामीटर के साथ एक चर, लेकिन आप तत्काल इसके साथ नहीं कर सकते हैं। जिसका अर्थ यह है कि आपके कन्स्ट्रक्टर में जेनेरिक क्लास में पारित किया गया हो सकता है जो कि उन प्रकारों को पकड़ने के लिए बनाया गया हो जो आप बाद में उपयोग करने की कोशिश कर रहे हैं। मामले में:

public class A { 
    public static void main(String[] args) { 
     TheClass<String> stringHolder = null; // should constrain parameters to strings 
     A a = new A(stringHolder); 
     a.donot(Float.valueOf(13)) ; // this is an example of what could happen 
    } 

    private TheClass<?> instance; 

    public A(TheClass<?> instance) { 
     this.instance = instance; 
    } 

    public void do(Object target) { 
     instance.theMethod(target); 
    } 
} 

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

कुछ लोगों ने सुझाव पढ़ने: Oracle Generics Trail

+0

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

+0

वैसे भी, आपका कोड रनटाइम पर असफल हो जाएगा, अपवाद फेंक देगा और प्रोग्राम को रोक देगा। यह ठीक है, यह एक निहित दावा की तरह है और त्रुटि उपयोगकर्ताओं को दिखाएगी कि उनके कोड में कोई गलती है। यह संकलन समय त्रुटि नहीं होगी, लेकिन यह अभी भी एक त्रुटि है और डीबग स्टैकट्रैक के साथ ताजा और साफ क्रैश नहीं होगा :) आपके उदाहरण के लिए +1 हालांकि, यह लोगों को यह समझने में मदद करेगा कि क्यों संकलन- समय सत्यापन महत्वपूर्ण है। –

+0

@ AurélienRibon - मैंने जो कोड पोस्ट किया है वह केवल चित्रण उद्देश्यों के लिए है। मैंने 'डू' विधि को 'डोनोट' में बदल दिया, लेकिन जहां तक ​​मैंने त्रुटियों को सही किया। – Perception

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