2009-12-08 16 views
29

मैं कक्षा में किसी फ़ील्ड के प्रकार को निर्धारित करने का प्रयास कर रहा हूं। मैंने सभी आत्मनिरीक्षण विधियों को देखा है लेकिन यह नहीं पता कि इसे कैसे किया जाए। इसका उपयोग जावा क्लास से एक्सएमएल/जेसन उत्पन्न करने के लिए किया जा रहा है। मैंने यहां कई प्रश्नों को देखा है लेकिन मुझे बिल्कुल वही नहीं मिला है जो मुझे चाहिए।मैं जावा में जेनेरिक फ़ील्ड के प्रकार को कैसे निर्धारित कर सकता हूं?

उदाहरण:

class Person { 
    public final String name; 
    public final List<Person> children; 
} 

जब मैं मार्शल इस वस्तु, मुझे पता है कि chidren फ़ील्ड प्रकार Person की वस्तुओं की एक सूची है की जरूरत है, तो मैं यह कर सकते हैं मार्शल ठीक से।

मैं

for (Field field : Person.class.getDeclaredFields()) { 
    System.out.format("Type: %s%n", field.getType()); 
} 

की कोशिश की थी लेकिन यह केवल मुझे बता देगा कि यह एक List, नहीं की Person रों

धन्यवाद

+1

सूची कि इन घोषणाओं, जो कई उपयोग के मामलों के लिए एक अच्छी शुरुआत होना चाहिए शामिल हैं? जब तक मैं बिंदु खो रहा हूँ। – Woot4Moo

+0

मेरा मतलब है कि –

उत्तर

50

एक List है जावा ट्यूटोरियल Trail: The Reflection API से Obtaining Field Types पर एक नज़र डालें ।

असल में, तुम क्या करने की जरूरत है अपने वर्ग के सभी java.lang.reflect.Field और उन्हें में से प्रत्येक पर Field#getType() (नीचे संपादित जांच) कॉल करने के लिए है। सभी सार्वजनिक क्षेत्रों, संरक्षित, पैकेज और निजी पहुंच फ़ील्ड समेत ऑब्जेक्ट फ़ील्ड प्राप्त करने के लिए, बस Class.getDeclaredFields() का उपयोग करें। कुछ इस तरह:

for (Field field : Person.class.getDeclaredFields()) { 
    System.out.format("Type: %s%n", field.getType()); 
    System.out.format("GenericType: %s%n", field.getGenericType()); 
} 

संपादित करें: के रूप में एक टिप्पणी में wowest से कहा, आप वास्तव में, Field#getGenericType() फोन की जाँच करता है, तो वापस आ Type एक ParameterizedType है और फिर उसके अनुसार मानकों को आकर्षित करने की जरूरत है। ParameterizedType#getRawType() औरका उपयोग क्रमशः ParameterizedType के प्रकार के तर्क के कच्चे प्रकार और सरणी प्राप्त करने के लिए करें।

for (Field field : Person.class.getDeclaredFields()) { 
    System.out.print("Field: " + field.getName() + " - "); 
    Type type = field.getGenericType(); 
    if (type instanceof ParameterizedType) { 
     ParameterizedType pType = (ParameterizedType)type; 
     System.out.print("Raw type: " + pType.getRawType() + " - "); 
     System.out.println("Type args: " + pType.getActualTypeArguments()[0]); 
    } else { 
     System.out.println("Type: " + field.getType()); 
    } 
} 

और उत्पादन होगा::

for (Field field : Person.class.getFields()) { 
     System.out.println(field.getType()); 
} 

कुंजी वर्ग Field

+4

पास्कल - आप बहुत करीब हैं। आप टाइप प्रकार = Field.getGenericType(); और फिर जांचें कि यह पैरामीटरेट टाइप है, फिर पैरामीटर को पकड़ें। यह एक खरगोश छेद होने के समाप्त होता है - पूछने वाले को सीमा निर्धारित करने या कुछ सुंदर फैंसी कोड लिखने के लिए तैयार होने की आवश्यकता होती है। – wowest

+0

धन्यवाद wowest, यह वही है जो मुझे पैरामीटरेटेड टाइप के साथ संयोजन में चाहिए .getRawType और पैरामीटरेट टाइप टाइप .getActualArguments। –

+0

मैं यह नहीं समझ सकता कि आपकी टिप्पणी को सही उत्तर के रूप में कैसे चिह्नित किया जाए, इसलिए मैं अपने स्वयं के प्रश्न का उत्तर दूंगा ताकि मैं –

3

इस स्निपेट ले निम्नलिखित कोड इस दर्शाता है java.lang.reflect.Field.getType के साथ मिटाए गए प्रकार को प्राप्त कर सकते हैं। आप सामान्य प्रकार Field.getGenericType (जिसमें वाइल्डकार्ड और बाध्य जेनेरिक पैरामीटर और पागलपन के सभी प्रकार हो सकते हैं) के साथ सामान्य प्रकार प्राप्त कर सकते हैं। आप Class.getDeclaredFields (Class.getFields के माध्यम से फ़ील्ड प्राप्त कर सकते हैं) आपको सार्वजनिक फ़ील्ड (सुपरर्टपी सहित) - व्यर्थ बताएंगे)। आधार प्रकार फ़ील्ड प्राप्त करने के लिए, Class.getSuperclass पर जाएं। Field.getModifiers से संशोधकों की जांच करने के लिए नोट - स्थिर फ़ील्ड शायद आपके लिए दिलचस्प नहीं होंगे।

+0

वह 'class.getFields' के साथ केवल सार्वजनिक फ़ील्ड (स्थिर सहित) है। इसके अलावा यह मिटाया गया प्रकार होगा। –

+0

तब मैंने – dfa

1

DFA बताते हैं, आप के रूप में है:

Field: name - Type: class java.lang.String 
Field: children - Raw type: interface java.util.List - Type args: class foo.Person 
4

यहाँ एक उदाहरण है कि मेरे सवाल का जवाब है

class Person { 
    public final String name; 
    public final List<Person> children; 
} 

//in main 
Field[] fields = Person.class.getDeclaredFields(); 
for (Field field : fields) { 
    Type type = field.getGenericType(); 
    System.out.println("field name: " + field.getName()); 
    if (type instanceof ParameterizedType) { 
    ParameterizedType ptype = (ParameterizedType) type; 
    ptype.getRawType(); 
    System.out.println("-raw type:" + ptype.getRawType()); 
    System.out.println("-type arg: " + ptype.getActualTypeArguments()[0]); 
    } else { 
    System.out.println("-field type: " + field.getType()); 
    } 
} 

यह आउटपुट

 
field name: name 
-field type: class java.lang.String 
field name: children 
-raw type:interface java.util.List 
-type arg: class com.blah.Person 
+0

डाउनवॉटर को गलत समझा, अगर आप डाउनवोट की व्याख्या करते हैं तो मैं जवाब में सुधार कर सकता हूं। –

4

मैं किसी भी ढांचे जो विरासत परतों के माध्यम से एक सामान्य क्षेत्र प्रकार निर्धारित करता है तो मैं कुछ लिखा है नहीं मिला है विधि:

यह तर्क क्षेत्र की जानकारी और वर्तमान ऑब्जेक्ट क्लास के माध्यम से प्रकार निर्धारित करता है।

लिस्टिंग 1 - तर्क:

public static Class<?> determineType(Field field, Object object) { 
    Class<?> type = object.getClass(); 
    return (Class<?>) getType(type, field).type; 
} 

protected static class TypeInfo { 
    Type type; 
    Type name; 

    public TypeInfo(Type type, Type name) { 
     this.type = type; 
     this.name = name; 
    } 

} 

private static TypeInfo getType(Class<?> clazz, Field field) { 
    TypeInfo type = new TypeInfo(null, null); 
    if (field.getGenericType() instanceof TypeVariable<?>) { 
     TypeVariable<?> genericTyp = (TypeVariable<?>) field.getGenericType(); 
     Class<?> superClazz = clazz.getSuperclass(); 

     if (clazz.getGenericSuperclass() instanceof ParameterizedType) { 
      ParameterizedType paramType = (ParameterizedType) clazz.getGenericSuperclass(); 
      TypeVariable<?>[] superTypeParameters = superClazz.getTypeParameters(); 
      if (!Object.class.equals(paramType)) { 
       if (field.getDeclaringClass().equals(superClazz)) { 
        // this is the root class an starting point for this search 
        type.name = genericTyp; 
        type.type = null; 
       } else { 
        type = getType(superClazz, field); 
       } 
      } 
      if (type.type == null || type.type instanceof TypeVariable<?>) { 
       // lookup if type is not found or type needs a lookup in current concrete class 
       for (int j = 0; j < superClazz.getTypeParameters().length; ++j) { 
        TypeVariable<?> superTypeParam = superTypeParameters[j]; 
        if (type.name.equals(superTypeParam)) { 
         type.type = paramType.getActualTypeArguments()[j]; 
         Type[] typeParameters = clazz.getTypeParameters(); 
         if (typeParameters.length > 0) { 
          for (Type typeParam : typeParameters) { 
           TypeVariable<?> objectOfComparison = superTypeParam; 
           if(type.type instanceof TypeVariable<?>) { 
            objectOfComparison = (TypeVariable<?>)type.type; 
           } 
           if (objectOfComparison.getName().equals(((TypeVariable<?>) typeParam).getName())) { 
            type.name = typeParam; 
            break; 
           } 
          } 
         } 
         break; 
        } 
       } 
      } 
     } 
    } else { 
     type.type = field.getGenericType(); 
    } 

    return type; 
} 

लिस्टिंग 2 - नमूने/टेस्ट:

class GenericSuperClass<E, T, A> { 
    T t; 
    E e; 
    A a; 
    BigDecimal b; 
} 

class GenericDefinition extends GenericSuperClass<Integer, Integer, Integer> { 

} 

@Test 
public void testSimpleInheritanceTypeDetermination() { 
    GenericDefinition gd = new GenericDefinition(); 
    Field field = ReflectionUtils.getField(gd, "t"); 
    Class<?> clazz = ReflectionUtils.determineType(field, gd); 
    Assert.assertEquals(clazz, Integer.class); 
    field = ReflectionUtils.getField(gd, "b"); 
    clazz = ReflectionUtils.determineType(field, gd); 
    Assert.assertEquals(clazz, BigDecimal.class); 
} 

class MiddleClass<A, E> extends GenericSuperClass<E, Integer, A> { } 

// T = Integer, E = String, A = Double 
class SimpleTopClass extends MiddleClass<Double, String> { } 

@Test 
public void testSimple2StageInheritanceTypeDetermination() { 
    SimpleTopClass stc = new SimpleTopClass(); 
    Field field = ReflectionUtils.getField(stc, "t"); 
    Class<?> clazz = ReflectionUtils.determineType(field, stc); 
    Assert.assertEquals(clazz, Integer.class); 
    field = ReflectionUtils.getField(stc, "e"); 
    clazz = ReflectionUtils.determineType(field, stc); 
    Assert.assertEquals(clazz, String.class); 
    field = ReflectionUtils.getField(stc, "a"); 
    clazz = ReflectionUtils.determineType(field, stc); 
    Assert.assertEquals(clazz, Double.class); 
} 

class TopMiddleClass<A> extends MiddleClass<A, Double> { } 

// T = Integer, E = Double, A = Float 
class ComplexTopClass extends TopMiddleClass<Float> {} 

@Test void testComplexInheritanceTypDetermination() { 
    ComplexTopClass ctc = new ComplexTopClass(); 
    Field field = ReflectionUtils.getField(ctc, "t"); 
    Class<?> clazz = ReflectionUtils.determineType(field, ctc); 
    Assert.assertEquals(clazz, Integer.class); 
    field = ReflectionUtils.getField(ctc, "e"); 
    clazz = ReflectionUtils.determineType(field, ctc); 
    Assert.assertEquals(clazz, Double.class); 
    field = ReflectionUtils.getField(ctc, "a"); 
    clazz = ReflectionUtils.determineType(field, ctc); 
    Assert.assertEquals(clazz, Float.class); 
} 

class ConfusingClass<A, E> extends MiddleClass<E, A> {} 
// T = Integer, E = Double, A = Float ; this class should map between a and e 
class TopConfusingClass extends ConfusingClass<Double, Float> {} 

@Test 
public void testConfusingNamingConvetionWithInheritance() { 
    TopConfusingClass tcc = new TopConfusingClass(); 
    Field field = ReflectionUtils.getField(tcc, "t"); 
    Class<?> clazz = ReflectionUtils.determineType(field, tcc); 
    Assert.assertEquals(clazz, Integer.class); 
    field = ReflectionUtils.getField(tcc, "e"); 
    clazz = ReflectionUtils.determineType(field, tcc); 
    Assert.assertEquals(clazz, Double.class); 
    field = ReflectionUtils.getField(tcc, "a"); 
    clazz = ReflectionUtils.determineType(field, tcc); 
    Assert.assertEquals(clazz, Float.class); 
    field = ReflectionUtils.getField(tcc, "b"); 
    clazz = ReflectionUtils.determineType(field, tcc); 
    Assert.assertEquals(clazz, BigDecimal.class); 
} 

class Pojo { 
    Byte z; 
} 

@Test 
public void testPojoDetermineType() { 
    Pojo pojo = new Pojo(); 
    Field field = ReflectionUtils.getField(pojo, "z"); 
    Class<?> clazz = ReflectionUtils.determineType(field, pojo); 
    Assert.assertEquals(clazz, Byte.class); 
} 

मैं आगे देख रहा हूँ आपकी प्रतिक्रियाओं का इंतज़ार!

+0

धन्यवाद! इस विधि ने बहुत मदद की। मैं जांच जोड़ना चाहूंगा कि टाइप.टाइप 'पैरामीटरेट टाइप टाइप' का एक उदाहरण है, इस मामले में '.getRawType()' विधि प्रकार उत्पन्न करती है। जब 'सूची ' टाइप होता है तो यह 'सूची' लाएगा। (अन्यथा यह 'पैरामीटरेट टाइप टाइप आईएमएल को java.lang.Class' पर नहीं डाला जा सकता है) –

1

यहां मेरा लेना है। यह हर संभव मामले को संभाल नहीं सकता है (और निश्चित रूप से कुछ कीड़े हैं), लेकिन यह मेरे कोड में अब तक होने वाले हर मामले को संभालता है।

private int            primitiveField1; 

    private Object            field1; 
    private List<Integer>          field2; 
    private Map<Integer, String>        field3; 
    private Map<? extends String, List<Map<Class<?>, Object>>> field4; 

    private char[]            array1; 
    private Character[]          array2; 
    private Class<? extends Integer>[]       array3; 
    private List<Integer>[]         array4; 

    private InnerClass<String>         innerClass; 

कार्यान्वयन::

public static String getDeclaration(Field field) { 
    return getDeclaration(field.getGenericType()); 
    } 

    private static String getDeclaration(Type genericType) { 
    if(genericType instanceof ParameterizedType) { 
     // types with parameters 
     ParameterizedType parameterizedType = (ParameterizedType) genericType; 
     String declaration = parameterizedType.getRawType().getTypeName(); 
     declaration += "<"; 

     Type[] typeArgs = parameterizedType.getActualTypeArguments(); 

     for(int i = 0; i < typeArgs.length; i++) { 
     Type typeArg = typeArgs[i]; 

     if(i > 0) { 
      declaration += ", "; 
     } 

     // note: recursive call 
     declaration += getDeclaration(typeArg); 
     } 

     declaration += ">"; 
     declaration = declaration.replace('$', '.'); 
     return declaration; 
    } 
    else if(genericType instanceof Class<?>) { 
     Class<?> clazz = (Class<?>) genericType; 

     if(clazz.isArray()) { 
     // arrays 
     return clazz.getComponentType().getCanonicalName() + "[]"; 
     } 
     else { 
     // primitive and types without parameters (normal/standard types) 
     return clazz.getCanonicalName(); 
     } 
    } 
    else { 
     // e.g. WildcardTypeImpl (Class<? extends Integer>) 
     return genericType.getTypeName(); 
    } 
    } 
+0

क्या आप टिप्पणी कर सकते हैं कि जावाबिकूल क्या कर सकता है? मुझे आश्चर्य है कि दोनों का मिश्रण रिकर्सिव जेनरिक प्लस विरासत को संभालने के लिए आवश्यक है। Https://stackoverflow.com/a/19363555/227299 –

+1

@JuanMendes javaBeCool एक अलग उपयोग केस को संबोधित करने के लिए प्रतीत होता है। मेरा जवाब एक स्ट्रिंग के रूप में फ़ील्ड घोषणा के बारे में है, मैं इसे कोड जनरेशन प्रोजेक्ट में उपयोग करता हूं। मेरा मूल प्रश्न इस प्रश्न के डुप्लिकेट के रूप में चिह्नित किया गया था - यही कारण है कि मैंने यहां पोस्ट किया (https://stackoverflow.com/q/45083186/1124509)। – Zalumon

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

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