2012-01-13 4 views
7

समस्या:जेनेरिक्स: एक मानचित्र में कुंजी और मूल्यों के बीच प्रतिबंध लागू करने के लिए कैसे

public static interface FunctionObject<T> { 
     void process(T object); 
    } 

मैं की जरूरत है यह सामान्य मैं टी का उपयोग करना चाहते है क्योंकि: मैं एक समारोह वस्तु इंटरफ़ेस एक वर्ग में परिभाषित किया गया है प्रक्रिया कार्यान्वयन में तरीकों।

Map<Class<T>, FunctionObject<T>> map; 

लेकिन मैं यह भी उप प्रकार वर्गों और के supertypes के समारोह वस्तुओं स्वीकार करने के लिए मैप हैं:
फिर, अन्य सामान्य वर्ग में, मैं एक नक्शा है, जहां मैं मूल्यों के रूप में कुंजी और समारोह वस्तुओं के रूप में वर्ग है कुंजी प्रकार है, तो मैंने किया था यह:

//if T were Number, this should be legal 
    map.put(Class<Integer>, new FunctionObject<Integer>(){...}); 
    map.put(Class<Float>, new FunctionObject<Number>(){...}); 
    map.put(Class<Double>, new FunctionObject<Object>(){...}); 

मैं चाहता हूँ के रूप में:

Map<Class<? extends T>, FunctionObject<? super T>> map; //not what I need 

मूल विचार के रूप में इस मानचित्र का उपयोग करने में सक्षम होना है

Map<Class<E extends T>, FunctionObject<? super E>>> map; 

मैं कैसे वांछित प्रभाव को प्राप्त कर सकते हैं: लागू FunctionObject वर्ग कुंजी या एक महाप्रकार के प्रकार है, क्या मैं वास्तव में परिभाषित करना चाहते हैं यह है? एक टाइपएफ़ हेटरोजेनस कंटेनर एकमात्र विकल्प है? मानचित्र जेनेरिक प्रकारों को संदर्भ से पॉप्युलेट करने की अनुमति देने के लिए कैसा लगेगा?

उत्तर

4

parametrized कंटेनर, बस अच्छा काम करने लगता है:

public class MyMap<T> 
{ 
    interface FunctionObject<X> {} 

    private Map<Class<? extends T>, FunctionObject<Object>> map = new HashMap<>(); 

    @SuppressWarnings("unchecked") 
    public <E extends T> void put(Class<E> c, FunctionObject<? super E> f) 
    { 
     map.put(c, (FunctionObject<Object>) f); 
    } 

    public <E extends T> FunctionObject<Object> get(Class<E> c) 
    { 
     return map.get(c); 
    } 

    public static void Main(String[] args) 
    { 
     MyMap<Number> map = new MyMap<>(); 

     map.put(Integer.class, new FunctionObject<Integer>() {}); 
     map.put(Float.class, new FunctionObject<Number>() {}); 
     map.put(Double.class, new FunctionObject<Object>() {}); 
    } 
} 

संपादित सवाल का पालन करने के लिए। अफसोस की बात है कि वस्तु को कम करने से बचने का कोई तरीका नहीं है।

संपादितget() गयी।

+0

उपयोग के मामले के आधार पर काम कर सकता है। –

+0

हां, लेकिन प्राप्त करने का क्रिया तब होता है जब मजा एक्सडी शुरू होता है। –

+0

'मिल()' ही कभी लौट सकते हैं 'FunctionObject ()': के बाद से पैरामीटर टी और चाबी का एक * सुपर क्लास * है, वहाँ एक ऊपरी बाध्य स्थापित करने के लिए कोई रास्ता नहीं है। मैंने इसे जवाब में जोड़ा। – Viruzzo

4

आप इसे encapsulation के साथ कर सकते हैं, मानते हैं कि आप केवल विधि के माध्यम से मानचित्र का उपयोग करते हैं जो प्रति प्रविष्टि आधार पर यह जांचता है।

निम्न जोड़ें विधि प्रकार को डबल करने की आवश्यकता से बचाती है।

public class Main { 
interface FunctionObject<T> { } 

private final Map<Class, FunctionObject> map = new LinkedHashMap<Class, FunctionObject>(); 

public <T> void add(FunctionObject<T> functionObject) { 
    Class<T> tClass = null; 
    for (Type iType : functionObject.getClass().getGenericInterfaces()) { 
     ParameterizedType pt = (ParameterizedType) iType; 
     if (!pt.getRawType().equals(FunctionObject.class)) continue; 
     Type t = pt.getActualTypeArguments()[0]; 
     tClass = (Class<T>) t; 
     break; 
    } 
    map.put(tClass, functionObject); 
} 

public <T> void put(Class<T> tClass, FunctionObject<T> functionObject) { 
    map.put(tClass, functionObject); 
} 

public <T> FunctionObject<T> get(Class<T> tClass) { 
    return map.get(tClass); 
} 

public static void main(String... args) throws IOException { 
    Main m = new Main(); 
    m.add(new FunctionObject<Integer>() { 
    }); 
    FunctionObject<Integer> foi = m.get(Integer.class); 
    System.out.println(foi.getClass().getGenericInterfaces()[0]); 
} 
} 

प्रिंट

Main.Main$FunctionObject<java.lang.Integer> 

आप @SuppressWarnings("unchecked") उपयोग कर सकते हैं यदि आप चेतावनी को निष्क्रिय करना चाहते।

बिंदु है; फ़ील्ड घोषणा में आपके पास मौजूद बाधा का वर्णन करने का कोई तरीका नहीं है, यदि आप एक्सेसर विधियों का उपयोग करते हैं तो आप एक ही परिणाम प्राप्त कर सकते हैं जो प्रति प्रविष्टि आधार पर चेक करता है। यदि आप कच्चे प्रकार सही हैं, तो आप रनटाइम चेक भी जोड़ सकते हैं।

+0

लेकिन यह केवल टाइप टी और कुछ और नहीं देता है, है ना? और वैसे, वह मानचित्र घोषणा कच्चे प्रकारों का उपयोग करने के लिए चेतावनी देती है। –

+5

हां, यह पीटर के जवाब का मुद्दा है: यह नक्शा नहीं है जो प्रकार की सुरक्षा की गारंटी देता है। यह तथ्य है कि मानचित्र में/से मूल्यों को रखने/प्राप्त करने का एकमात्र तरीका इन विधियों का उपयोग करना है, जो हमेशा कक्षा कक्षा के साथ एक फ़ंक्शन को संबद्ध करते हैं। बेशक, यदि आप इन विधियों को कॉल करते समय कच्चे प्रकार का उपयोग करते हैं, तो आपके पास कोई गारंटी नहीं है। –

+0

ठीक है, इसलिए टाइपएफ़ कंटेनर को कोड करने के अलावा कोई विकल्प नहीं है। मुझे आश्चर्य है कि यह सी # में समान है। –

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

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