2011-11-29 16 views
5

पर लागू नहीं किया जा सकता है मेरे पास कोड है जिसमें Map (संदेश) हैंडलर हैं। मैं हैंडलर जेनरेट करने की कोशिश कर रहा हूं (जैसा कि इंटरफेस हैंडलर द्वारा देखा गया है)। जेनेरिकों के बिना हैंडलर को ऑब्जेक्ट से संबंधित वर्ग में डालने की ज़रूरत होती है, जो बचने के लिए अच्छा होगा (लेकिन सबकुछ काम करता है)। प्रत्येक संदेश वर्ग (Foo नीचे) के लिए मेरे पास हैंडलर क्लास है।जावा जेनरिक: कैप्चर ऑब्जेक्ट

मैं किसी भी प्रकार के हैंडलर के किसी भी प्रकार का मानचित्र कैसे रख सकता हूं और Object "बस" के साथ कॉल/कॉल कर सकता हूं? (handleMessage(Object) पर पैरामीटर प्रतिबंधित नहीं किया जा सकता है)

नीचे MWE देखें।

import java.util.*; 
public class Logic 
{ 
    Map<Class<?>, Handler<?>> handlers = new HashMap<Class<?>, Handler<?>>(); 

    public void run() 
    { 
     handlers.put(Foo.class, new FooHandler()); 
    } 

    public void handleMessage(Object msg) 
    { 
     Handler<?> handler = handlers.get(msg.getClass()); 
     if (handler != null) { 
      handler.execute(msg); 
     } 
    } 

    private interface Handler<T> 
    { 
     public void execute(T msg); 
    } 

    private class FooHandler implements Handler<Foo> 
    { 
     public void execute(Foo msg) {} 
    } 

    private class Foo {} 
} 

इस कोड का उत्पादन:

Logic.java:16: निष्पादित Logic.Handler में (कब्जा # की एक्स?) लागू नहीं किया जा सकता है> (java.lang.Object) हैंडलर के लिए। निष्पादित (एमएसजी);

हैंडलर इंटरफेस जेनेरिक रखते हुए इसे काम करने के लिए कैसे मरम्मत की जा सकती है?

उत्तर

6

आप किसी क्षेत्र में कुंजी और मान के बीच संबंध को परिभाषित नहीं कर सकते हैं, लेकिन आप इसे लागू करने के लिए एक्सेसर विधियों का उपयोग कर सकते हैं, बशर्ते केवल इन विधियों का उपयोग मानचित्र तक पहुंचने के लिए किया जाता है।

private final Map<Class, Handler> handlers = new HashMap<Class, Handler>(); 

public <T> void addHandler(Class<T> clazz, Handler<T> handler) { 
    handlers.put(clazz, handler); 
} 

@SuppressWarnings("unchecked") 
public <T> Handler<T> getHandler(Class<T> clazz) { 
    return (Handler<T>) handlers.get(clazz); 
} 

@SuppressWarnings("unchecked") 
public <T> Handler<T> getHandlerFor(T t) { 
    return getHandler((Class<T>) t.getClass()); 
} 

public void run() { 
    addHandler(Foo.class, new FooHandler()); 
} 

public <T> void handleMessage(T msg) { 
    Handler<T> handler = getHandlerFor(msg); 
    if (handler != null) { 
     handler.execute(msg); 
    } 
} 
+0

आपके उत्तर ने मुझे सुरक्षित विषम कंटेनरों, जेनेरिक प्रकारों के लिए रिश्तों और क्या नहीं लिखने का नेतृत्व किया! मैं थोड़ा निराश हूं कि रैपर विधियों और @Suppress चेतावनी के बिना यह असंभव है हालांकि: <। फिर भी, यह अब काम करता है, लेकिन मुझे नहीं पता कि यह यहां जेनरिक पेश करने की परेशानी के लायक है या नहीं। –

+0

समस्या यह है कि आप जेनेरिक वाक्यविन्यास कितना जटिल चाहते हैं। ;) यह जोड़ने के लिए कॉल की जांच करेगा, हैंडलर, हेटहैंडलर और getHandlerFor सही हैं। –

2

समस्या यह है कि Object की तुलना में अधिक विशिष्ट है, कि execute() एक निश्चित पैरामीटर प्रकार लेता है।

हालांकि, आपके handleMessage() विधि में, संकलक को पता नहीं है कि पैरामीटर किस प्रकार का है। मान लीजिए कि FooHandler कक्षा Bar (जो संभव होगा) के लिए पंजीकृत है।

इस संदर्भ handler.execute(msg); में वास्तव में FooHandler#execute(Foo) में परिणाम होगा एक Bar तर्क है, जो एक ClassCastException (Bar extends Foo जब तक) में परिणाम होगा साथ बुलाया जा रहा है। इस प्रकार संकलक उस कोड को संकलित करने से इंकार कर देता है।

+0

अच्छा बिंदु वहाँ! –

1

एक और उत्तर जो यहां नहीं था, लेकिन यह होना चाहिए - सभी जेनेरिक वाक्यविन्यास को हटा दें (यानी सभी <?> हटाएं)। फिर पार्सर जेडीके 1.4 वाक्यविन्यास पर वापस आ जाएगा और यह सब ठीक काम करेगा।

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