Java反射:在继承类中获取字段值

3

可能重复:
如何通过Java反射访问继承的私有字段

您好,我在使用Java反射时遇到了初始化值的问题。

我有一个简单的类:

 public class A extends B {
     private String name;
 }

  public class B {
     private String superName;   
  }

另外,我还有一个简单的函数:

   public void createRandom(Class<T> clazz , List<String> classFields){


    try {
        T object = clazz.newInstance();
        for(String s : classFields){
            clazz.getDeclaredField(s);
        }

    } catch(Exception e){

    }

   }

我的函数做其他事情,但是我遇到了问题,因为出现了错误:

java.lang.NoSuchFieldException: superName

如何使用反射设置所有类字段和超类字段?

我已经获取了所有类字段(包括继承的字段),并且正在使用函数field.set(Object obj, Object value),但是这种方式无法设置继承的类字段:/

我没有问题可以获取所有类字段,我正在使用Spring ReflectionUtils.doWithfield。我将所有字段名称存储在List<String> classField中,因此我知道所有clazz字段也继承下来的字段。但我的问题是如何将值设置到所有clazz字段中。


你是如何调用 createRandom() 的?clazz 和列表的值是什么? - amit
4个回答

8

如果我猜的没错的话,你正在类A上调用此方法,并期望能够查看在类B中声明的底层字段,像这样:

A.class.getDeclaredField("superName");

这并不是实际情况,会抛出异常 (java.lang.NoSuchFieldException)。反射不会检查超类以查找字段或方法。所以由于类A未定义superName,使用反射也无法找到它。但是,您可以修改代码使其检查所有超类,直到达到null作为超类为止,在此时,如果仍然找不到,则明确不存在。
以下是示例:
public static Field findUnderlying(Class<?> clazz, String fieldName) {
    Class<?> current = clazz;
    do {
       try {
           return current.getDeclaredField(fieldName);
       } catch(Exception e) {}
    } while((current = current.getSuperclass()) != null);
    return null;
}

这里有一个示例调用:findUnderlying(A.class, "superName");它首先检查类A是否有该字段。由于A没有该字段,循环会继续到它的超类B(非null则继续)。B有该字段,因此它返回该字段。如果B没有该字段,则会检查Object,然后返回null,因为Object没有超类。


这个方法很好,但是你永远不应该重新分配一个方法参数(在这种情况下是clazz)。 - aymeric
@aymeric 嗯,谢谢,实际上我之前就是这样编辑的,但后来改了,当时没想到 :) - Alex Coleman
但我知道如何获取所有类字段(包括继承的)。但我的问题是如何设置所有字段的值?我只发现一种方法可以做到这一点:field.set(Object obj,Object value),但此方法无法设置继承的字段 :/ - Łukasz Woźniczka
如果您调用 someFieldOfSuperClass.set(subClassOfClassWithField, value),它仍然可以工作。 - Alex Coleman

6

您可以使用:

clazz.getSuperclass().getDeclaredField(s);

使用try-catch的替代方案(或者在某些情况下,可以和try-catch一起使用):

clazz.getDeclaredField(s);

编辑:

要设置超类的值,请使用以下方法:

Field f = clazz.getSuperclass().getDeclaredField(s);
f.setAccessible(true); // Especially necessary if the field is not public
f.set(yourObject, theValue);

是的,我知道。但是我怎么能将值设置到继承类字段中呢? - Łukasz Woźniczka

1

-1
即使 A 继承自 B,也无法在 A 的实例中工作,这是因为子类中的私有成员不可访问。尝试将 superName 的访问权限更改为 protected,看看是否可行...

1
我认为在类定义中更改可见性并不是解决方案,OP正在寻找访问私有字段的方法。 - Marek Sebera
不改变可见性,允许您将值保存到具有私有修饰符的字段中。 - Łukasz Woźniczka

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接