2010-04-28 24 views
16

कहें कि किसी भी तरह से किसी अन्य वर्ग से ऑब्जेक्ट संदर्भ प्राप्त हुआ है:ऑब्जेक्ट के कन्स्ट्रक्टर (प्रतिबिंब) के पैरामीटर नाम कैसे प्राप्त करें?

Object myObj = anObject; 

अब मैं इस ऑब्जेक्ट की कक्षा प्राप्त कर सकता हूं:

Class objClass = myObj.getClass(); 

अब, मैं इस वर्ग के सभी निर्माता प्राप्त कर सकता हूं:

Constructor[] constructors = objClass.getConstructors(); 

अब, मैं प्रत्येक कन्स्ट्रक्टर को लूप कर सकता हूं:

if (constructors.length > 0) 
{ 
    for (int i = 0; i < constructors.length; i++) 
    { 
     System.out.println(constructors[i]); 
    } 
} 

यह पहले से ही मुझे कन्स्ट्रक्टर का एक अच्छा सारांश दे रहा है, उदाहरण के लिए एक कन्स्ट्रक्टर सार्वजनिक टेस्ट (स्ट्रिंग पैरामनाम) को सार्वजनिक टेस्ट (जावा। lang.String)

मुझे कक्षा प्रकार देने के बजाय, मैं पैरामीटर का नाम प्राप्त करना चाहता हूं .. इस मामले में "paramName"। मुझे यह कैसे करना है? मैंने बिना सफलता के निम्नलिखित प्रयास किए:

if (constructors.length > 0) 
    { 
     for (int iCon = 0; iCon < constructors.length; iCon++) 
     { 
      Class[] params = constructors[iCon].getParameterTypes(); 
      if (params.length > 0) 
      { 
       for (int iPar = 0; iPar < params.length; iPar++) 
       { 
        Field fields[] = params[iPar].getDeclaredFields(); 
        for (int iFields = 0; iFields < fields.length; iFields++) 
        { 
         String fieldName = fields[i].getName(); 
         System.out.println(fieldName); 
        }          
       } 
      } 
     } 
    } 

दुर्भाग्यवश, यह मुझे अपेक्षित परिणाम नहीं दे रहा है। क्या कोई मुझे बता सकता है कि मुझे यह कैसे करना चाहिए या मैं क्या गलत कर रहा हूं? धन्यवाद!

+1

यह ** जावा 8 ** में प्रतिबिंब के माध्यम से संभव है, [यह SO उत्तर] (http://stackoverflow.com/a/21455958/573057) देखें - [paranamer] पर दस्तावेज़ पढ़ने से प्राप्त (https: //github.com/paul-hammant/paranamer) नीचे डंकन मैकग्रेगर के उत्तर से। – earcam

उत्तर

11

यह जानकारी संकलन के बाद खो गई है और रनटाइम पर पुनर्प्राप्त नहीं की जा सकती है।

+0

क्या आप निश्चित हैं? तो एक कन्स्ट्रक्टर का इलाज अन्य तरीकों से अलग तरीके से किया जाता है? – Tom

+0

@ टॉम: संकलक के बाद न तो कन्स्ट्रक्टर और न ही विधियां पैरामीटर नाम बनाए रखती हैं। –

+0

http://stackoverflow.com/questions/471693/using-reflection-to-get-method-name-and-parameters जॉन स्कीट एक उत्तर में कहते हैं "आप प्रतिबिंब से विधि पैरामीटर मान प्राप्त नहीं कर सकते हैं। आप प्राप्त कर सकते हैं पैरामीटर नाम और प्रकार, लेकिन पैरामीटर स्वयं नहीं। " - यही कारण है कि मुझे विश्वास था कि यह संभव था, लेकिन मुझे लगता है कि वह गलत था। हालांकि धन्यवाद। – Tom

16

Roman's answer पर टिप्पणी में उल्लेख किया है, पैरामीटर नाम पुनः प्राप्त किया जा सकता है अगर संकलक डिबगिंग प्रतीकों शामिल है, हालांकि मानक जावा प्रतिबिंब एपीआई के माध्यम से नहीं। नीचे एक उदाहरण कि किस प्रकार आप ASM bytecode library का उपयोग कर डिबगिंग प्रतीकों के माध्यम से पैरामीटर नाम प्राप्त कर सकते हैं है:

/** 
* Returns a list containing one parameter name for each argument accepted 
* by the given constructor. If the class was compiled with debugging 
* symbols, the parameter names will match those provided in the Java source 
* code. Otherwise, a generic "arg" parameter name is generated ("arg0" for 
* the first argument, "arg1" for the second...). 
* 
* This method relies on the constructor's class loader to locate the 
* bytecode resource that defined its class. 
* 
* @param constructor 
* @return 
* @throws IOException 
*/ 
public static List<String> getParameterNames(Constructor<?> constructor) throws IOException { 
    Class<?> declaringClass = constructor.getDeclaringClass(); 
    ClassLoader declaringClassLoader = declaringClass.getClassLoader(); 

    Type declaringType = Type.getType(declaringClass); 
    String constructorDescriptor = Type.getConstructorDescriptor(constructor); 
    String url = declaringType.getInternalName() + ".class"; 

    InputStream classFileInputStream = declaringClassLoader.getResourceAsStream(url); 
    if (classFileInputStream == null) { 
     throw new IllegalArgumentException("The constructor's class loader cannot find the bytecode that defined the constructor's class (URL: " + url + ")"); 
    } 

    ClassNode classNode; 
    try { 
     classNode = new ClassNode(); 
     ClassReader classReader = new ClassReader(classFileInputStream); 
     classReader.accept(classNode, 0); 
    } finally { 
     classFileInputStream.close(); 
    } 

    @SuppressWarnings("unchecked") 
    List<MethodNode> methods = classNode.methods; 
    for (MethodNode method : methods) { 
     if (method.name.equals("<init>") && method.desc.equals(constructorDescriptor)) { 
      Type[] argumentTypes = Type.getArgumentTypes(method.desc); 
      List<String> parameterNames = new ArrayList<String>(argumentTypes.length); 

      @SuppressWarnings("unchecked") 
      List<LocalVariableNode> localVariables = method.localVariables; 
      for (int i = 0; i < argumentTypes.length; i++) { 
       // The first local variable actually represents the "this" object 
       parameterNames.add(localVariables.get(i + 1).name); 
      } 

      return parameterNames; 
     } 
    } 

    return null; 
} 

इस उदाहरण का उपयोग करता है एएसएम लाइब्रेरी की tree API। यदि गति और स्मृति कीमती है, तो आप इसके बजाय visitor API का उपयोग करने के लिए उदाहरण को दोबारा कर सकते हैं।

12

अतः, वास्तव में, आप मुझे यह सही करने के लिए एक मौजूदा जवाब संपादित करने के लिए कम से कम 30 वर्ण दर्ज करने जा रहे हैं भगवान के लिए https://github.com/paul-hammant/paranamer

ओह की कोशिश करो।

+0

टिप के लिए धन्यवाद! बहुत अच्छा काम करता है। – Ciddan

+0

लिंक को एक लॉगिन की आवश्यकता है। – javamonkey79

+0

कोडेहॉस बंद कर दिया गया था, नए गीथब घर –

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

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