40

クラス内のフィールドのタイプを判別しようとしています。私はすべてのイントロスペクション方法を見てきましたが、それを行う方法を完全には理解していません. これは、Java クラスから xml/json を生成するために使用されます。ここでいくつかの質問を見てきましたが、必要なものが正確に見つかりませんでした。

例:

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

このオブジェクトをマーシャリングするとき、chidrenフィールドが type のオブジェクトのリストであることを知る必要があるPersonため、適切にマーシャリングできます。

私は試していた

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

しかし、これはそれが であり、のでListはないことだけを教えてくれますListPerson

ありがとう

4

8 に答える 8

65

Java チュートリアルトレイルからフィールド タイプを取得する: リフレクション API を参照してください。

基本的に、必要なことは、すべてjava.lang.reflect.Fieldのクラスを取得して、それぞれを呼び出すField#getType()ことです(以下の編集を確認してください)。public、protected、package、および private アクセス フィールドを含むすべてのオブジェクト フィールドを取得するには、単純に を使用します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が指摘したように、実際には を呼び出し、返されたものが aであるField#getGenericType()かどうかを確認し、それに応じてパラメーターを取得する必要があります。と を使用して、それぞれa の生の型と型引数の配列を取得します。次のコードはこれを示しています。TypeParameterizedTypeParameterizedType#getRawType()ParameterizedType#getActualTypeArgument()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());
    }
}

そして出力します:

Field: name - Type: class java.lang.String
Field: children - Raw type: interface java.util.List - Type args: class foo.Person
于 2009-12-08T17:04:29.097 に答える
6

これが私の質問に答える例です

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());
  }
}

この出力

フィールド名:名前
-フィールドタイプ:クラスjava.lang.String
フィールド名:子供
-raw type:interface java.util.List
-タイプ引数:クラスcom.blah.Person
于 2009-12-08T19:03:09.573 に答える
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);
}

フィードバックをお待ちしております。

于 2013-10-14T15:19:02.637 に答える
3

このスニペットを取ります:

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

キークラスはフィールドです

于 2009-12-08T17:05:43.973 に答える
1

dfaが指摘しているように、消去されたタイプは。で取得できますjava.lang.reflect.Field.getType。でジェネリック型を取得できますField.getGenericType(ワイルドカードとバインドされたジェネリックパラメーター、およびあらゆる種類の狂気が含まれている可能性があります)。あなたはフィールドを通り抜けることができますClass.getDeclaredFieldsClass.getFieldsあなたにパブリックフィールド(supertpyeのものを含む)を与えるでしょう-無意味です)。基本タイプのフィールドを取得するには、を実行しClass.getSuperclassます。-静的フィールドからの修飾子をチェックすることに注意してくださいField.getModifiers。おそらくあなたにとって興味がないでしょう。

于 2009-12-08T17:22:42.087 に答える