2008-11-25 6 views
15

क्या जावा में ऑब्जेक्ट को संयुक्त जेनेरिक प्रकार में डालना संभव है? अगर मैं एक वर्ग है कि दोनों इंटरफेस (फू & बार) को लागू करता हैमुझे जावा जेनेरिक के लिए कई सीमाओं के साथ कैसे डालना चाहिए?

public static <T extends Foo & Bar> void doSomething(T object) { 
    //do stuff 
} 

इस विधि कॉलिंग कोई समस्या नहीं है:

मैं की तरह एक विधि है।

समस्या तब होती है जब मुझे इस विधि को कॉल करने की आवश्यकता होती है जिसे मुझे पास करने की आवश्यकता होती है जिसे java.lang.Object के रूप में प्राप्त किया जाता है और मुझे इसे कंपाइलर को खुश करने के लिए इसे डालने की आवश्यकता होती है। लेकिन मैं यह नहीं समझ सकता कि इस कलाकार को कैसे बनाया जाए।

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

समस्या इस तरह एक समारोह में निहित है:

public void problemFunction (Object o) { 
    if (o instanceof Foo && o instanceof Bar) { 
     doSomething((Problematic cast) o); 
    } 
} 

}

उत्तर

12

दुर्भाग्य से, वहाँ कोई कानूनी डाली है कि आप इस स्थिति को पूरा करने के कर सकते हैं। आपको एक ही प्रकार का होना चाहिए जिसे आप सीमाओं के रूप में आवश्यक सभी इंटरफेस को लागू करने के लिए जाना जाता है, ताकि आप इसे ला सकें। यह एक प्रकार हो सकता है जिसे आप उद्देश्य, या कुछ मौजूदा प्रकार के लिए बनाते हैं।

interface Baz extends Foo, Bar { } 

public void caller(Object w) { 
    doSomething((Baz) w); 
} 

अन्य प्रकार के लिए जाने जाते हैं, तो Baz की तरह, सीमा को पूरा करने के बाद, आप उन प्रकार के लिए परीक्षण कर सकते हैं, और अपने कॉलर कि उन प्रकार के लिए एक कलाकारों के साथ doSomething कॉल में एक शाखा है। यह सुंदर नहीं है।

आप प्रतिनिधिमंडल का भी उपयोग कर सकते हैं, अपनी खुद की कक्षा Baz बना सकते हैं जो doSomething द्वारा आवश्यक सीमाओं को पूरा करता है। फिर उस ऑब्जेक्ट को लपेटें जिसे आप अपने Baz वर्ग के उदाहरण में पारित कर चुके हैं, और उस रैपर को doSomething पर पास करें।

private static class FooBarAdapter implements Foo, Bar { 
    private final Object adaptee; 
    FooBarAdapter(Object o) { 
    adaptee = (Foo) (Bar) o; 
    } 
    public int flip() { return ((Foo) adaptee).flip(); } 
    public void flop(int x) { ((Foo) adaptee).flop(x); } 
    public void blort() { ((Bar) adaptee).blort(); } 
} 

public void problemFunction (Object o) { 
    doSomething(new FooBarAdapter(o)); 
} 
+0

अच्छा विचार है:

doSomething((Problematic cast) o); 

बस इस के लिए हो जाता है। मैंने इसे थोड़ा अलग तरीके से इस्तेमाल किया। मैं 2 अलग-अलग प्रकार के ऑब्जेक्ट्स प्राप्त करने के लिए FooBarAdapter को प्राथमिकता देता हूं। == का उपयोग यह जांचने के लिए किया जा सकता है कि यह एक ही वस्तु है (कोई जरूरी नहीं है)। इस तरह, उनका संकलन समय प्रकार की जांच है। –

+1

मैंने इस प्रतिनिधि पैटर्न को अज्ञात/नामित आंतरिक विधि वर्गों को एक ऑब्जेक्ट "कास्ट" करने के लिए जोड़ा जो मुझे बाध्य आवश्यकताओं के लिए कक्षाओं और इंटरफेस के एक सेट को विस्तार/कार्यान्वित करने के लिए जानता है। जॉन का जवाब देखें: http://stackoverflow.com/a/9514406/910718 –

+0

और यह जावा भाषा की सीमा प्रतीत होता है क्योंकि स्कैला में एक ही JVM पर चल रहा है, यह o.asInstanceOf [बार के साथ फू] के रूप में आसान है। –

-1

समाधान के लिए, यदि आप किसी अन्य इंटरफेस FooBar कि फू और बार फैली को परिभाषित करने और अपने वर्ग को लागू कर सकते हैं। यह भी एक शीर्ष-स्तर इंटरफ़ेस होना जरूरी नहीं है - आप यह घोषणा करते यह निजी यदि आप ऊपर को अस्त-व्यस्त करने या अपने कोड के बाकी पुनः स्थापित नहीं करना चाहते कर सकते हैं:

private interface FooBar extends Foo, Bar {} 
public void problemFunction (Object o) { 
    if (o instanceof Foo && o instanceof Bar) { 
     doSomething((FooBar) o); 
    } 
} 
+1

मुझे विश्वास है कि यह काम नहीं करेगा क्योंकि वास्तव में कोई गारंटी नहीं है कि वास्तव में "FooBar लागू करता है"। मुझे नहीं लगता कि जावा बस इसे मान लेगा। – ArtB

+0

@ArtB उत्तर कहता है "और आपकी कक्षा ने इसे कार्यान्वित किया है।" – cquezel

7
public static <T extends Foo & Bar> void doSomething(T object) 

यह निरूपित करने के लिए लगता है कि आप ऑब्जेक्ट पर एक से अधिक ऑपरेशन कर रहे होंगे।

मैं तर्क दूंगा कि यदि आप ऑब्जेक्ट पर वांछित ऑपरेशंस कर रहे हैं तो इंटरफेस में अलग होने के लिए पर्याप्त हैं, तो वे अपने स्वयं के तरीकों के लायक होने के लिए काफी अलग हैं।

यह संभावना है कि आप वांछित ऑपरेशन करने के लिए अलग-अलग तरीकों को कॉल करने के लिए इस कोड को पुन: स्थापित कर सकते हैं। यह पूरे ऑपरेशन को ग्राहक के परिप्रेक्ष्य से अधिक स्पष्ट कर सकता है।

बजाय:

public void problemFunction (Object o) { 
    if (o instanceof Foo && o instanceof Bar) { 
     doSomething((Problematic cast) o); 
    } 
} 

यह हो जाता है:

public void problemFunction(Object o) { 
    if (o instanceof Foo && o instanceof Bar) { 
     fooifySomething((Foo) o); 
     baratizeSomething((Bar) o); 
    } 
} 
+1

एलएमएओ fooify, यह मेरे लिए नया है xD – Goodwine

5

यह संभव है करने के लिए "ऊपर से डाली" एक संघ प्रकार के, में संघ प्रकार एन्कोडिंग की भयानक तरह से एक विधि का प्रकार पैरामीटर; आपके उदाहरण के लिए आप

private <Q extends Foo & Bar> Q upcast(final Object in) { 
    return (Q) in; 
} 

// ... elsewhere... 

if (myObject instanceof Foo && myObject instanceof Bar) { 
    doSomething(upcast(myObject)); 
} 
+0

धन्यवाद। केवल परेशानी यह एक अनचेक कास्ट उत्पन्न करता है। हालांकि मैंने एक संशोधित संस्करण का उपयोग किया जो ऑब्जेक्ट की बजाय फू लेता है और चेक करता है कि यह बार लागू करता है और फिर कलाकारों के साथ लौटता है जैसा आपने अन्यथा क्लासकास्ट अपवाद फेंक दिया है। –

14

जावा 8 casting with additional bounds की संभावना का परिचय दे सकता है। आप Object को class के रूप में कई interfaces (या केवल interfaces) के साथ डाले जा सकते हैं।

तो यह:

doSomething((Foo & Bar) o); 
+0

अद्यतन के लिए हाल ही में इस बारे में पढ़ें – pvgoddijn