【问题标题】:Get value of unknown class field获取未知类字段的值
【发布时间】:2013-07-23 19:40:10
【问题描述】:

我有一堆未知的类存储在List/Array。 如何从这些类中获取字段的值?

我应该在f.get() 中粘贴什么?

for(Class<?> cl : ClassList){
        for(Field f : cl.getFields()){
            try {
                f.setAccessible(true);
                writeln(f.get( <WHAT TO PASTE HERE> ));
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

【问题讨论】:

  • 其他库很好,但我不能使用除了我的主 jar 之外的任何文件我也不能创建那个未知类的新实例。那个未知的类是 Bukkit API 的 Plugin 类
  • 请说明您到底想做什么?没有实际实例(即对象)就无法读取实例字段。如果您只有Classes,您将只能读取静态字段值。也许你有来自classList 的类实例的集合?或者没有classList而是一个objectList?我可以用 Java 反射 API 给你写一个例子,但我必须理解这个问题。

标签: java class reflection field


【解决方案1】:

就反射而言,我更喜欢依赖具有更可读 API 的框架,而不是标准的 Java 反射 API。我用过两个:

第一个是Mirror。获取字段值(静态或实例)如下所示:

获取静态字段的值:

Class clazz;
Object value = new Mirror().on(clazz).get().field("fieldName");

获取实例字段的值:

Object target;
Object value = new Mirror().on(target).get().field("fieldName");

您也可以传递 java.lang.reflect.Field 而不是 fieldName String。

获取静态字段的值:

Field aField;
Class clazz;
Object value = new Mirror().on(clazz).get().field(aField);

FEST-Reflect 是另一个不错的库(FEST fluent Assertions 真的很不错,顺便说一句)。

import static org.fest.reflect.core.Reflection.*;

// Retrieves the value of the field "name"
String name = field("name").ofType(String.class).in(person).get();

// Retrieves the value of the field "powers"
List<String> powers = field("powers").ofType(new TypeRef<List<String>>() {})
                                     .in(jedi).get();

// Retrieves the value of the static field "count" in Person.class
int count = field("count").ofType(int.class).in(Person.class).get();


// Retrieves the value of the static field "commonPowers" in Jedi.class
List<String> commmonPowers = field("commonPowers")
                                    .ofType(new TypeRef<List<String>>() {})
                                    .in(Jedi.class).get();

所有示例均取自相应库的文档。

基于您提供的代码的一些快速粗略的示例: 用 Mirror 实现你想要的(如果我理解正确的话):

for(Class<?> cl : classList){
   Mirror mirror = new Mirror().on(cl);
   for(Field f: mirror.reflectAll().fields()) {
      if(java.lang.reflect.Modifier.isStatic(f.getModifiers()) {
         writeln(mirror.get().field(f));
      }
   }
}

我假设您只想读取静态字段。对于对象列表:

for(Object obj : objectList){
   for(Field f: new Mirror().on(obj.getClass()).reflectAll().fields()) {
       writeln(new Mirror().on(obj).get().field(f));
   }
}

与 FEST-Reflect 相同:

for(Class<?> cl : classList){
    for(Field f : cl.getFields()){
      if(java.lang.reflect.Modifier.isStatic(f.getModifiers()) {
         writeln(field(f.getName()).ofType(f.getType()).in(cl).get());
      }
    }
}

和:

for(Object obj : objectList){
   for(Field f: obj.getClass().getFields()) {
      if(!java.lang.reflect.Modifier.isStatic(f.getModifiers()) { //not 100% sure if this is required
         writeln(field(f.getName()).ofType(f.getType()).in(obj).get());
      }
   }
}

注意,如果没有实际的类实例(对象)来读取它们,您将无法读取实例字段值。

我希望这会有所帮助。当然,这些示例可以使用一些重构。

【讨论】:

    【解决方案2】:

    您拥有的字段仅指向一个字段,而不是特定对象中的特定字段,并且您必须有一个对象才能从中获取字段值。参数必须是从中提取字段值的对象。如果对象的类型错误,则抛出IllegalArgumentException。所以要小心。这里有一个 sn-p 来说明:

    Field field = Integer.class.getDeclaredField("value"); // I think that's the field name
    int val = field.get(new Integer(8)); // returns 8
    int val2 = field.get("Hello"); // throws IllegalArgumentException
    

    【讨论】:

    • 请务必附上您的答案(否则为正确答案),并附上代码 sn-p,以使其对未来的读者更有用
    • 方法field.get(obj) 有一个Object 返回类型,所以您必须将返回值转换为Integer,否则它不会编译。对于原始类型,使用getInt()等方法更方便。
    • 确实如此。我应该提到这一点。
    猜你喜欢
    • 1970-01-01
    • 2021-08-05
    • 2016-03-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-06-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多