72

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

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

但它不起作用。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
4

9 回答 9

91
obj = obj.getClass().getSuperclass().cast(obj);

这条线没有做你期望它做的事情。转换 anObject实际上并没有改变它,它只是告诉编译器把它当作别的东西。

例如,您可以将 a 强制List转换为 a Collection,但它仍然是 a 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();
}

顺便说一句,如果您可以访问 Spring 框架,则有一种方便的方法可以遍历类和所有超类的字段:( 另请参阅我以前的答案:通过 Java 中的反射访问私有继承字段
ReflectionUtils.doWithFields(baseClass, FieldCallback)

于 2013-04-30T09:14:15.853 回答
46

getDeclaredFields()为您提供该类的所有字段,包括private那些。

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

如果你想要超类的private/protected方法,你将不得不反复调用getSuperclass()然后调用getDeclaredFields()超类对象。

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

于 2013-04-30T09:16:04.067 回答
22

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

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;
    }
于 2017-11-21T13:13:29.967 回答
5

试试这些

如何读取 Java 中的私有字段?

Java中是否可以通过反射访问私有字段

Field.setAccessible(true) 是您必须做的才能通过反射访问它

import java.lang.reflect.Field;

class B 
{
    private int i = 5;
}

public class A extends B 
{
    public static void main(String[] args) throws Exception 
    {
        A a = new A();
        Field[] fs = a.getClass().getSuperclass().getDeclaredFields();
        for (Field field : fs)
        {
            field.setAccessible(true);
            System.out.println( field.get( a ) );
        }
    }
}
于 2013-04-30T09:00:29.753 回答
5

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

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

allFieldsFor(SomeClass.class).map(Field::getName).forEach(System.out::println);

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

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

以下方法是从 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
    );
}
于 2018-01-24T22:11:47.610 回答
2

要获取超类字段,请使用getSuperclass(). 从那里你可以得到超类的领域。

于 2013-04-30T09:04:55.483 回答
0

您必须在提取值之前设置setAccessible为。true有时JVM不允许提取私有变量,它可能会给出安全异常。

ClassName obj  =  new ClassName();
Field field  =   ClassName.class.getDeclaredField  ("name of the field");
field.setAccessible   (true);
DataType value  =  (DataType) field.get  (obj);
于 2013-04-30T09:12:41.640 回答
0

以前问过。

通过 Java 中的反射访问私有继承字段

在您的代码中,设置field.setAccessible(true);

于 2013-04-30T09:16:06.670 回答
-1

这是一个解决方案

//我的对象

    Student student =new Student();

    Field[] field2=student.getClass().getSuperclass().getDeclaredFields();
    Field[] field1=student.getClass().getDeclaredFields();
    
    Field [] all_Fields=new Field[field1.length+field2.length];
    
    
    //Joining field 1 and two
      System.arraycopy(field2, 0, all_Fields, 0, field2.length);
      System.arraycopy(field1, 0, all_Fields, field2.length, field1.length);
    

      //Printing all fields
    for(Field i:all_Fields)
    {
        System.out.println(i);
    }

//如果要从多个超类中获取字段,则可以使用以下代码进行迭代:

    Class clazz = Student.class;
    while (clazz != null) {
      clazz= clazz.getSuperclass(); 
    }
于 2020-09-17T14:37:21.850 回答