使用泛型获取所有字段

时间:2017-03-30 09:49:50

标签: java generics

任务: 您需要获取指定类的所有字段,包括来自所有超类的私有和包含字段。 Usuall方法是重新获得字段:

private static void getAllFieldsRecursive(List<Field> fields, Class<?> type) {
    fields.addAll(Arrays.asList(type.getDeclaredFields()));   
    if (type.getSuperclass() != null) {
        getAllFieldsRecursive(fields, type.getSuperclass());
    }
}

然而,案例并未涵盖被覆盖的字段。 运行代码:

class A {String myfield; String otherAField}
class B extends class A {String myField; String otherBField}

会给出结果: String B.myfield; String B.otherBField; String A.myfield,String A.otherField

使用Set无济于事,因为String A.myfield不等于B.myfield

下面的解决方案

1 个答案:

答案 0 :(得分:0)

/**
 * Collect all fields declared, including superclasses.
 * @param type class
 * @return
 */
public static List<Field> getAllFields(Class<?> type) {
    List<Field> fields = new ArrayList<>();
    getAllFieldsRecursive(fields, type);
    return fields;
}

/**
 * Get fields recursively, starting from child.
 * Starting from child is important to support fields overriding.
 * @param fields all fields collected
 * @param type currently scanned class
 * Example:
 * class A {String myfield; String otherField}
 * class B extends class A {String myField; String bField}
 * Result: String B.myfield; String B.bField; String A.otherField
 */
private static void getAllFieldsRecursive(List<Field> fields, Class<?> type) {
    List<Field> declaredFields = Arrays.asList(type.getDeclaredFields()); //Start from child
    for (Field declaredField : declaredFields){
        if (!genericContainsField(declaredField, fields))
            fields.add(declaredField); //if field is not overridden in child, add it
    }
    if (type.getSuperclass() != null) {
        getAllFieldsRecursive(fields, type.getSuperclass());
    }
}

/**
 *
 * @param declaredField field we are comparing
 * @param fields current fields list
 * @return
 */
private static boolean genericContainsField(Field declaredField, List<Field> fields){
    for (Field field:fields){
        if (genericEqualsFields(field, declaredField))
            return true;
    }
    return false;
}

/**
 * Compares this {@code Field} against the specified object.  Returns
 * true if the objects are the same.  Two {@code Field} objects are the same if
 * they were have the same name and type.
 * Declared by the same class is NOT needed
 * Hack for Generic lookup, based on Field.equals()
 */
private static boolean genericEqualsFields(Field obj, Field other) {
    return (obj.getName() == other.getName())
            && (obj.getType() == other.getType());
}