2012-05-21 17 views
7

आशा है कि कोई इस भ्रम से मेरी मदद कर सकता है। क्रम में यह सुनिश्चित करें कि कुंजी के रूप में इस्तेमाल वर्ग MyInterface में पैरामीटर के रूप में इस्तेमाल किया वर्ग के रूप में एक ही है बनाने के लिएजावा जेनेरिक पास पैरामीटर

public static <T> void myMethod(Map<Class<T>, MyInterface<T>> map) { 
} 

प्रयुक्त पैरामीटर टी:

मैं इस विधि बनाया है।

अब मैं एक नक्शा पास करना चाहता हूं जो अलग-अलग वर्गों को चाबियाँ, निश्चित रूप से, और MyInterface के अनुरूप कार्यान्वयन के रूप में अलग करना चाहता है।

लेकिन यह काम नहीं करता है, टाइप पैरामीटर के कारण वाक्यविन्यास त्रुटियां प्राप्त कर रहा है। यहां कोड है, मुझे उम्मीद है कि आत्म व्याख्यात्मक है।

import java.util.HashMap; 
    import java.util.Map; 

    public class Test { 

    public static void main(String[] args) { 
     Map<Class<?>, MyInterface<?>> map = new HashMap<Class<?>, MyInterface<?>>(); 

    //  Map<Class<Object>, MyInterface<Object>> map = new HashMap<Class<Object>, MyInterface<Object>>(); 

     map.put(Object.class, new MyObjectImpl()); 

     //if I use Map<Class<Object>, MyInterface<Object>> I get a compiler error here 
     //because map<String> is not map<Object> basically 
     map.put(String.class, new MyStringImpl()); 

     //this would be possible using <?>, which is exactly what I don't want 
    //  map.put(String.class, new MyIntegerImpl()); 

     //<?> generates anyways a compiler error 
     myMethod(map); 
    } 

    //use T to make sure the class used as key is the same as the class of the parameter "object" in doSomething 
    public static <T> void myMethod(Map<Class<T>, MyInterface<T>> map) { 

    } 

    interface MyInterface<T> { 
     void doSomething(T object); 
    } 

    static class MyObjectImpl implements MyInterface<Object> { 
     @Override 
     public void doSomething(Object object) { 
      System.out.println("MyObjectImpl doSomething"); 
     } 
    } 

    static class MyStringImpl implements MyInterface<String> { 
     @Override 
     public void doSomething(String object) { 
      System.out.println("MyStringImpl doSomething"); 
     } 
    } 

    static class MyIntegerImpl implements MyInterface<Integer> { 
     @Override 
     public void doSomething(Integer object) { 
      System.out.println("MyIntegerImpl doSomething"); 
     } 
    } 
} 
+0

कक्षा 'Impl' में समाप्त होने वाले नाम आम तौर पर अधिक इंजीनियरिंग (जैसे इसका अर्थ है के लक्षण हैं (नीचे दिए गए उदाहरण की तरह) MapConstraints.constrainedMap उपयोग करने के लिए किया जाएगा , जिसे लागू नहीं किया जा सकता है)। – Romain

+1

इसके बारे में भूल जाओ, यह काम नहीं कर सकता है। जेनेरिक केवल एक समरूप मानचित्र परिभाषित कर सकते हैं।आप प्रवेश-दर-प्रविष्टि आधार पर कुछ भी लागू नहीं कर सकते हैं, केवल सभी मानचित्र प्रविष्टियों के लिए एक ही चीज़। –

+0

@ ठीक है, वास्तविक नाम इस तरह नहीं हैं, बस एक स्पष्ट उदाहरण बनाने के लिए लिखा है। लेकिन आपकी टिप्पणी भी लागू हो सकती है। आपका क्या मतलब है कि इसका मतलब केवल 1 कार्यान्वयन है, मेरे पास 3 है? – Ixx

उत्तर

8

आप कोई बाधा Map के put() में परिभाषित किया गया है क्योंकि कि, ऐसा नहीं कर सकते key और value के बीच विधि। आपको आश्वस्त करना है कि अपने मानचित्र को ठीक तरह से भर जाता है चाहते हैं (यानी ऐसी बाधा बनाने), कुछ एपीआई के पीछे नक्शा है कि उदाहरण के लिए शुद्धता की जांच करेंगे, छिपाने:

public <T> void registerInterface(Class<T> clazz, MyInterface<T> intf) { 
    map.put(clazz, intf); 
} 

फिर, बस registerInterface फोन के बजाय मैन्युअल रूप से पॉप्युलेट नक्शा।

+0

map.put (क्लैज, intf) मुझे लगता है :) – Aif

+0

@ एआईएफ, धन्यवाद - सही। – npe

0

मुझे नहीं लगता कि यह संभव है:

मूल्य के रूप में Class<T> ही कभी स्वीकार करता T.classClass<Object>String.class स्वीकार नहीं करेगा, भले ही ऑब्जेक्ट स्ट्रिंग का एक सुपरक्लास है।

इस कारण से Class<T> के साथ कोई भी नक्शा कुंजी के रूप में T.class के साथ केवल एक तत्व हो सकता है, जो T का मान भी है।

कंपाइलर केवल टी के पैरामीटर के निश्चित मूल्य के साथ एक मानचित्र स्वीकार करेगा। आप Map<Class<?>, MyInterface<?>> लिख सकते हैं क्योंकि प्रत्येक? माना जाता है कि यह अलग है: यह Map<Class<T>, MyInterface<T>> से मेल नहीं खाता है जिसके लिए टी को समान मान होना आवश्यक है।

उसने कहा, myMethod केवल एकल प्रविष्टि मानचित्र स्वीकार करेगा, जो उपयोगी प्रतीत नहीं होता है।

public static <T> void myMethod(Map<Class<? extends T>, MyInterface<? extends T>> map) { 

} 

करने के लिए अपने विधि हस्ताक्षर अब अपनी घोषणा और मंगलाचरण काम करना चाहिए

0

बदलें ..

Map<Class<?>, MyInterface<?>> map = new HashMap<Class<?>, MyInterface<?>>(); 
    map.put(Integer.class, new MyIntegerImpl()); 
    map.put(String.class, new MyStringImpl()); 
    map.put(Object.class, new MyObjectImpl()); 
    myMethod(map); 
+0

लेकिन यह नक्शा अभी भी आपको 'map.put (Integer.class, MyStringImpl()) करने की अनुमति देता है;' जो प्रश्न में बिल्कुल नहीं पूछा गया है। बीटीडब्ल्यू, ओपी ने पहले ही सुझाव दिया है कि उनके प्रश्न में। –

3

जहाँ तक मुझे पता है, आप जावा में वर्णित एक मानचित्र घोषित नहीं कर सकते हैं। आप जो भी कर सकते हैं वह टाइपिंग और/या बाधाओं को जोड़ रहा है।

अमरूद ClassToInstanceMap के साथ आपकी समस्या का समाधान करने वाला कुछ प्रदान करता है। तो एक तरह से यह करने के लिए किसी दिए गए इंटरफ़ेस का केवल एक कार्यान्वयन है

import java.text.ParseException; 
import java.util.HashMap; 
import java.util.Map; 

import com.google.common.collect.MapConstraint; 
import com.google.common.collect.MapConstraints; 

public class Main { 

    interface MyInterface<T> { 
     void doSomething(T object); 

     Class<T> getType(); 
    } 

    static class MyObjectImpl implements MyInterface<Object> { 
     @Override 
     public void doSomething(Object object) { 
      System.out.println("MyObjectImpl doSomething"); 
     } 

     @Override 
     public Class<Object> getType() { 
      return Object.class; 
     } 
    } 

    static class MyStringImpl implements MyInterface<String> { 
     @Override 
     public void doSomething(String object) { 
      System.out.println("MyStringImpl doSomething"); 
     } 

     @Override 
     public Class<String> getType() { 
      return String.class; 
     } 
    } 

    static class MyIntegerImpl implements MyInterface<Integer> { 
     @Override 
     public void doSomething(Integer object) { 
      System.out.println("MyIntegerImpl doSomething"); 
     } 

     @Override 
     public Class<Integer> getType() { 
      return Integer.class; 
     } 
    } 

    public static void main(String[] args) throws ParseException { 

     Map<Class<?>, MyInterface<?>> map = MapConstraints.constrainedMap(new HashMap<Class<?>, Main.MyInterface<?>>(), 
       new MapConstraint<Class<?>, MyInterface<?>>() { 
        @Override 
        public void checkKeyValue(Class<?> key, MyInterface<?> value) { 
         if (value == null) { 
          throw new NullPointerException("value cannot be null"); 
         } 
         if (value.getType() != key) { 
          throw new IllegalArgumentException("Value is not of the correct type"); 
         } 
        } 
       }); 
     map.put(Integer.class, new MyIntegerImpl()); 
     map.put(String.class, new MyStringImpl()); 
     map.put(Object.class, new MyObjectImpl()); 
     map.put(Float.class, new MyIntegerImpl()); //<-- Here you will get an exception 
    } 
} 
+0

+1 क्योंकि बहुत ही जानकारीपूर्ण है लेकिन मेरा उत्तर मेरी वर्तमान राय में अधिक सामान्य है। – Ixx

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