从类中获取所有字段(甚至私有和继承)

Mic*_*man 52 java reflection

我正在做大学项目.
我需要从课堂上获得所有领域.甚至私人和继承.我试图获取所有声明的字段,然后转换为超类并重复.我的代码片段:

private void listAllFields(Object obj) {
    List<Field> fieldList = new ArrayList<Field>();
    while (obj != null) {
        fieldList.addAll(Arrays.asList(obj.getClass().getDeclaredFields()));
        obj = obj.getClass().getSuperclass().cast(obj);
    }
    // rest of code
Run Code Online (Sandbox Code Playgroud)

但它不起作用.tmpObj在铸造之后仍然是同一个类(不是超类).
我将不胜感激任何帮助如何解决铸造问题,或如何以不同的方式检索这些字段.

问题不是获取字段的访问权限,而是获取字段的名称!
我这样管理它:

private void listAllFields(Object obj) {
    List<Field> fieldList = new ArrayList<Field>();
    Class tmpClass = obj.getClass();
    while (tmpClass != null) {
        fieldList.addAll(Arrays.asList(tmpClass .getDeclaredFields()));
        tmpClass = tmpClass .getSuperclass();
    }
    // rest of code
Run Code Online (Sandbox Code Playgroud)

Sea*_*oyd 82

obj = obj.getClass().getSuperclass().cast(obj);
Run Code Online (Sandbox Code Playgroud)

这条线不符合您的预期.转换Object实际上并没有改变它,它只是告诉编译器将其视为其他东西.

例如,你可以投出ListCollection,但它仍然会保持一个List.

但是,通过超类循环访问字段可以正常工作而不需要强制转换:

Class<?> current = yourClass;
while(current.getSuperclass()!=null){ // we don't want to process Object.class
    // do something with current's fields
    current = current.getSuperclass();
}
Run Code Online (Sandbox Code Playgroud)

顺便说一句,如果你有权访问Spring Framework,有一个方便的方法来循环遍历类和所有超类的字段:( 另见我之前的答案:通过Java中的反射访问私有继承字段)
ReflectionUtils.doWithFields(baseClass, FieldCallback)


Tom*_*yre 34

getDeclaredFields()为您提供该类的所有字段,包括其中private的字段.

getFields()为您提供public该类及其超类的所有字段.

如果你想要private/ protectedSuper Classes的方法,你将不得不重复调用getSuperclass()然后调用getDeclaredFields()Super Class对象.

这里没有任何内容在javadocs中没有明确解释


Ade*_*lin 11

这是我用来获取对象的所有字段的方法

private <T> List<Field> getFields(T t) {
        List<Field> fields = new ArrayList<>();
        Class clazz = t.getClass();
        while (clazz != Object.class) {
            fields.addAll(Arrays.asList(clazz.getDeclaredFields()));
            clazz = clazz.getSuperclass();
        }
        return fields;
    }
Run Code Online (Sandbox Code Playgroud)

  • 你是战士兄弟 (2认同)

Chr*_*s K 5

该解决方案使用 Java 8 流,对于那些正在学习 Java 函数式编程的人很有用。它按照其他答案迭代 getSuperclass 和 getDeclaredFields,但它以功能方式进行。

以下行将打印在 SomeClass 或其任何超类上找到的每个字段名称的名称。

allFieldsFor(SomeClass.class).map(Field::getName).forEach(System.out::println);
Run Code Online (Sandbox Code Playgroud)

下面是通过超类来创建字段流的代码。

private Stream<Field> allFieldsFor( Class c ) {
    return walkInheritanceTreeFor(c).flatMap( k -> Arrays.stream(k.getDeclaredFields()) );
}

private Stream<Class> walkInheritanceTreeFor( Class c ) {
    return iterate( c, k -> Optional.ofNullable(k.getSuperclass()) );
}
Run Code Online (Sandbox Code Playgroud)

以下方法是从 Streams.iterate 建模的,但是 Streams.iterate 旨在创建无限流。此版本已修改为在从 fetchNextFunction 返回 Optional.none() 时结束。

private <T> Stream<T> iterate( T seed, Function<T,Optional<T>> fetchNextFunction ) {
    Objects.requireNonNull(fetchNextFunction);

    Iterator<T> iterator = new Iterator<T>() {
        private Optional<T> t = Optional.ofNullable(seed);

        public boolean hasNext() {
            return t.isPresent();
        }

        public T next() {
            T v = t.get();

            t = fetchNextFunction.apply(v);

            return v;
        }
    };

    return StreamSupport.stream(
        Spliterators.spliteratorUnknownSize( iterator, Spliterator.ORDERED | Spliterator.IMMUTABLE),
        false
    );
}
Run Code Online (Sandbox Code Playgroud)