2009-11-19 13 views
5

मैं एक कक्षा में एक विधि परिभाषित किया है:जावा प्रतिबिंब: मेरे संग्रह में क्या शामिल है?

public void setCollection(Collection<MyClass>); 

और एक अन्य वर्ग

public void setCollection(Collection<OtherClass>); 

में (और वास्तव में, इसी तरह के वर्गों के बहुत सारे)

सभी एक ही साथ कक्षाओं में हैं superclass, और मेरे पास एक समर्थन-वर्ग में एक विधि है जहां मैं इस विधि को कॉल करना चाहता हूं और इसे सही वर्ग प्रकार के आइटमों के साथ सेट करना चाहता हूं। अब, मुझे लगता है कि मैं

Method setter = ...; 
Class<?> paramClass = setter.getParameterTypes()[0]; // Is Collection in this case 
if(paramClass.equals(Collection.class)) { 
    HashSet col = new HashSet(); 
    // fill the set with something 
    setter.invoke(this, col); 
} 

करके एक संग्रह सेट कर रहा हूं प्राप्त कर सकते हैं लेकिन यह कैसे मैं यह पता लगाने की क्या वर्ग इस संग्रह में वस्तुओं से संबंधित होना चाहिए करते हैं?

चीयर्स

Nik

उत्तर

9
Method.getGenericParameterTypes(); 

पैरामीटर स्वीकार करने वाले प्रकारों की एक सरणी देता है। जटिलता वहां से तेजी से बढ़ जाती है।

अपने विशिष्ट मामले में, यह काम करेगा:

Method m = Something.class.getMethod("setCollection", Collection.class); 
    Class<?> parameter = (Class<?>) ((ParameterizedType) m.getGenericParameterTypes()[0]).getActualTypeArguments()[0]; 

लेकिन संभावित gotchas का एक बहुत कैसे पैरामीटर घोषित किया गया था पर निर्भर करता है वहाँ देखते हैं,। यदि यह आपके उदाहरण में बहुत आसान है, तो बढ़िया। यदि नहीं, तो GetGenericParameterTypes() विधि और getActualTypeArguments() विधि में दोनों प्रकार के समूह हैं, जिनके लिए आपको खाता होना है। यह बहुत बालों वाली और बदसूरत बहुत तेज हो जाता है।

+0

धन्यवाद एक गुच्छा, इसने मेरी समस्या हल की! यहां जोड़ा गया जटिलता समग्र रूप से मेरी जटिलता को कम कर देगी, इसलिए मैं आपके लिए अपनी टोपी लेता हूं और ईमानदारी से धन्यवाद देता हूं। :-) – niklassaers

1

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

आप कुछ अतिरिक्त जानकारी here पा सकते हैं।

अद्यतन:

अपने आप को ठीक करने के लिए, इस पद्धति पर विचार करें:

public <T> String doSomething(T first, int second) { 
    return first.toString(); 
} 

बाइट कोड में, यह निम्न हस्ताक्षर करना होगा (टी प्रकार ध्यान दें):

<T:Ljava/lang/Object;>(TT;I)Ljava/lang/String 

तो मैंने ऊपर जो कहा वह केवल इस अपवाद के साथ सच है।

0

आपको पहले से ही सेटटर पता है। तो मुझे ऐसा लगता है कि, इस मामले में, MyClass और अन्य क्लास (संग्रह नहीं, लेकिन आइटम) एक समान इंटरफ़ेस का कुछ साझा करते हैं। उस स्थिति में आपको वास्तव में सटीक प्रकार को जानने की आवश्यकता नहीं है।

0

जैसा कि कैंडीरु ने पहले ही समझाया है, 'संग्रह प्रकार' मिटा दिया गया है, रनटाइम पर यह ऑब्जेक्ट प्रकारों का संग्रह नहीं है।

:

आप तो आप एक दूसरा पैरामीटर जो 'संग्रह प्रकार' की जानकारी रखता गुजारें सकता थोड़ा

public void setCollection(Collection<T> aCollection, Class<T> elementType); 

करने के लिए अपने उपवर्गों में संदेश हस्ताक्षर बदलने की अनुमति कर रहे हैं, उपयोग जैसा होगा

public void setCollection(Collection<MyClass> myClassCollection, 
          Class<MyClass> clazz); 

और इसका इस्तेमाल करने के लिए:

Collection<MyClass> myClassCollection = new ArrayList<MyClassCollection>(); 
setCollection(myClassCollection, MyClass.class); 

लेकिन दूसरी तरफ - अमूमन सहयोगी आपको इसके बारे में परवाह नहीं है क्योंकि प्रकार रनटाइम पर मिटा दिया गया है और आप किसी भी प्रकार की ऑब्जेक्ट को एक पैरामीटर संग्रह में डाल सकते हैं, जब तक आप कंपाइलर द्वारा कैच नहीं किया जाता है;)

2

मैं विचार करूंगा सेट कोलेक्शन विधियों को अपने स्वयं के वर्गों में ले जाना और फिर कुछ और करना (आप इसे एक समय में एक तत्व के रूप में करने के बजाए पूरे संग्रह को बनाने के लिए बदल सकते हैं)।

इस प्रतिबिंब से छुटकारा और यह सुनिश्चित करता है कि यह यह संकलन समय पर typesafe हो जाता है। मैं गलत समझ सकता हूं कि आप क्या करने की कोशिश कर रहे हैं, लेकिन मुझे लगता है कि मुझे यह मिला। "Init" विधि सहायक विधि होगी (कम से कम अगर मैं समझता हूं कि आप किस उद्देश्य के लिए लक्षित हैं)।

public class Main 
{ 
    public static void main(String[] args) 
    { 
     List<Car> car; 
     List<Bar> bar; 

     car = new ArrayList<Car>(); 
     bar = new ArrayList<Bar>(); 
     init(car, new CarCreator()); 
     init(bar, new BarCreator()); 
    } 

    private static <T> void init(final List<T> list, 
           final Creator<T> creator) 
    { 
     for(int i = 0; i < 10; i++) 
     { 
      final T instance; 

      instance = creator.newInstance(i); 
      list.add(instance); 
     } 
    } 
} 

interface Foo 
{  
} 

class Bar implements Foo 
{ 
} 

class Car implements Foo 
{ 
} 

interface Creator<T> 
{ 
    T newInstance(int i); 
} 

class BarCreator 
    implements Creator<Bar> 
{ 
    public Bar newInstance(final int i) 
    { 
     return (new Bar()); 
    } 
} 

class CarCreator 
    implements Creator<Car> 
{ 
    public Car newInstance(final int i) 
    { 
     return (new Car()); 
    } 
} 
संबंधित मुद्दे