2010-12-23 8 views
7

मेरे पास पैरामीटरयुक्त इंटरफ़ेस है जो कई अलग-अलग तरीकों से लागू किया गया है। रन टाइम पर मुझे पता लगाना चाहिए कि एक मनमानी ऑब्जेक्ट दिया गया है जो इंटरफ़ेस को लागू करता है, इंटरफ़ेस के वास्तविक प्रकार पैरामीटर क्या हैं।परोक्ष रूप से लागू जेनेरिक इंटरफ़ेस के लिए वास्तविक प्रकार के तर्क कैसे प्राप्त करें?

यहाँ समस्या को वर्णन करने के एक टुकड़ा है, और एक आधे रास्ते इसे हल करने का प्रयास (also on ideone.com) है:

import java.util.*; 
import java.lang.reflect.*; 

interface Awesome<X> { } 
class Base<E> implements Awesome<Set<E>> { } 
class Child extends Base<List<Integer>> { } 

class AwesomeExample {  
    public static void main(String[] args) { 
     Awesome<Set<List<Integer>>> x = new Child(); 

     System.out.println(
      ((ParameterizedType) 
       Child.class.getGenericSuperclass() 
      ).getActualTypeArguments()[0] 
     ); 
     // prints "java.util.List<java.lang.Integer>" 

     System.out.println(
      ((ParameterizedType) 
       Base.class.getGenericInterfaces()[0] 
      ).getActualTypeArguments()[0] 
     ); 
     // prints "java.util.Set<E>"   

     investigate(x); 
     // we want this to print "Set<List<Integer>>" 
    } 

    static void investigate(Awesome<?> somethingAwesome) { 
     // how to do this? 
    } 
} 

ऐसा लगता है जैसे वहाँ कार्यावधि में काफी सामान्य प्रकार की जानकारी निकालना कि:

  • Child extends Base<List<Integer>>
  • Base<E> implements Awesome<Set<E>>

और इसलिए हम सभी बिट और टुकड़ों को एक साथ कि समाप्त करने के लिए रख सकते हैं:

  • Child implements Awesome<Set<List<Integer>>>

तो ऐसा लगता है कि समस्या की तरह व्याख्या करने योग्य है, लेकिन यह इतना आसान नहीं है, क्योंकि हम चाहते हैं एक मनमाना वर्ग/इंटरफेस पदानुक्रम के साथ काम करने के लिए। क्या यह ऐसा करने का एकमात्र तरीका है? क्या कोई आसान तरीका है? क्या किसी ने पहले से ऐसा करने के लिए पुस्तकालय लिखा है?

+0

मुझे ऐसी लाइब्रेरी से अवगत नहीं है जो इसे लागू करता है। मैंने इसे स्वयं किया - और यह बहुत सुखद नहीं था। मुझे कम से कम एक सुपर प्रकार टोकन कार्यान्वयन मिल सकता है: http://code.google.com/p/google-gson/source/browse/trunk/src/main/java/com/google/gson/reflect/TypeToken.java ? आर = 60 और spec = svn89 –

उत्तर

-1

संक्षिप्त उत्तर नहीं है। मैं मानता हूं कि यह एक दयालुता है ... :( कारण यह है कि जावा संकलन चरण में टाइप पैरामीटर छोड़ देता है। वे बाइट कोड में मौजूद नहीं हैं। इन्हें केवल कंपाइलर द्वारा उपयोग किया जाता है।

आपकी समस्या का समाधान करने के लिए अभी तक इस प्रकार कक्षा की एक और "नियमित" पैरामीटर जोड़ने और इसे निर्माता के पास जब आप बेस का उदाहरण बनाकर कर रहे हैं करने के लिए है:

class Base<E> implements Awesome<Set<E>> { 
    private E type; 
    public Base(E type) { 
     this.type = type; 
    } 
} 
+2

प्रकार की जानकारी बाइट कोड में है। तो आप सही नहीं हैं। आप इस स्थिति में प्रकार की जानकारी प्राप्त कर सकते हैं। उदाहरण के लिए सुपर टाइप टोकन के लिए Google। –

+1

@ थॉमस - स्टेटिक टाइप जानकारी संग्रहीत है, गतिशील जानकारी नहीं है। – OrangeDog

4

संपादित करें: http://code.google.com/p/gentyref/

: तुम बस का उपयोग कर में देखना चाहते हो सकता है यदि आप गारंटी दे सकते हैं कि Awesome<?> के सभी कार्यान्वयन में तर्क तर्क नहीं होंगे, तो निम्न सह डी आप [1] आरंभ करना चाहिए:

static void investigate(Object o) { 
    final Class<?> c = o.getClass(); 
    System.out.println("\n" + c.getName() + " implements: "); 
    investigate(c, (Type[])null); 
} 

static void investigate(Type t, Type...typeArgs) { 
    if(t == null) return; 

    if(t instanceof Class<?>) { 
     investigate((Class<?>)t, typeArgs); 
    } else if(t instanceof ParameterizedType) { 
     investigate((ParameterizedType)t, typeArgs); 
    } 
} 

static void investigate(Class<?> c, Type...typeArgs) { 
    investigate(c.getGenericSuperclass(), typeArgs); 

    for(Type i : c.getGenericInterfaces()) { 
     investigate(i, typeArgs); 
    } 
} 

static void investigate(ParameterizedType p, Type...typeArgs) { 
    final Class<?> c = (Class<?>)p.getRawType(); 
    final StringBuilder b = new StringBuilder(c.getName()); 
    b.append('<'); 
    Type[] localArgs = p.getActualTypeArguments(); 
    if(typeArgs != null && typeArgs.length > 0) { 
     int i = 0, nextTypeArg = 0; 
     for(Type local : localArgs) { 
      if(local instanceof ParameterizedType) { 
       ParameterizedType localP = (ParameterizedType) local; 
       b.append(localP.getRawType()).append('<'); 
       b.append(typeArgs[nextTypeArg++]); 
       b.append('>'); 
      } else if(local instanceof TypeVariable) { 
       // reify local type arg to instantiated one. 
       localArgs[nextTypeArg] = typeArgs[nextTypeArg]; 
       b.append(localArgs[nextTypeArg]); 
       nextTypeArg++; 
      } else { 
       b.append(local.toString()); 
      } 
      b.append(", "); 
      i++; 
     } 
     if(typeArgs.length > 0) { 
      b.delete(b.length() - 2, b.length()); 
     } 
     b.append('>'); 
    } else { 
     String args = Arrays.toString(localArgs); 
     b.append(args.substring(1, args.length()-1)).append('>'); 
    } 
    System.out.println(b); 
    investigate(c, localArgs); 
} 

अगर, हालांकि, Awesome<?> या Base<E> की instantiations किया जाएगा, कि प्रकार की जानकारी विलोपन की वजह से नष्ट हो जाएंगे। यह चारों ओर, एक सम्मेलन के रूप में, कुछ के साथ इस तरह से काम किया जा सकता है:

Awesome<?> awesome = new Base<Double>() {}; 

सूचना {}, इस नए अनाम वर्ग कि औजार बनाता है (या यहां फैली) Base<E>। इस वर्ग में इसके प्रकार के पैरामीटर प्रतिबिंब के लिए उपलब्ध होंगे।

class Base<E> implements Awesome<Set<E>> { 

    public static Base<Number> newNumberInstance() { 
     return new Base<Number>() {}; 
    } 

    protected Base() {} 
} 

जैसा कि ऊपर कोड पूरी तरह से परीक्षण नहीं किया गया, आप क्या करना चाहते हो सकता है:

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

[1] यह & के सभी इंटरफेस को मुद्रित करेगा, न केवल Awesome के प्रकार पैरामीटर। इसे बदला जा सकता है, लेकिन मुझे लगा कि मैं अधिक सामान्य & के लिए जाना चाहूंगा ताकि आप विनिर्देशों को पूरा कर सकें। उदाहरण के लिए, आप को देखने के लिए मैं क्या मतलब है इन परीक्षण करने के लिए चाहता हूँ:

investigate(new ArrayList<Integer>()); 
investigate(new ArrayList<String>() {}); // new anonymous ArrayList class 
investigate(""); 
investigate(new Awesome<Comparable<?>>() {}); // new anonymous implementation of Awesome 
0

@ oconnor0 के प्रस्ताव के बाद, यहाँ कैसे gentyref साथ यह करने के लिए है:

static Type investigate(Awesome<?> somethingAwesome) { 
    return GenericTypeReflector.getTypeParameter(somethingAwesome.getClass(), Awesome.class.getTypeParameters()[0]); 
} 

मामले में somethingAwesome.getClass() हो सकता है सामान्य भी, यह GenericTypeReflector.addWildcardParameters के माध्यम से इसे पास करने के लिए उपयोगी हो सकता है।

वसंत में GenericTypeResolver.resolveTypeArgument(Class,Class) भी है जो एक ही परिणाम प्राप्त कर सकता है।

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

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