如何在Java中遍历Class属性?

qyswt5oh  于 2023-11-15  发布在  Java
关注(0)|答案(7)|浏览(158)

如何在java中动态地循环一个类的属性。
例如:

public class MyClass{
    private type1 att1;
    private type2 att2;
    ...

    public void function(){
        for(var in MyClass.Attributes){
            System.out.println(var.class);
        }
    }
}

字符串
这在Java中可能吗?

s8vozzvw

s8vozzvw1#

没有语言上的支持来完成你的要求。
您可以在运行时使用反射以反射方式访问类型的成员(例如,使用Class.getDeclaredFields()获取Field的数组),但这可能不是最佳解决方案,具体取决于您要做的事情。

另请参阅

相关问题

示例

下面是一个简单的例子,展示了反射的一些功能。

import java.lang.reflect.*;

public class DumpFields {
    public static void main(String[] args) {
        inspect(String.class);
    }
    static <T> void inspect(Class<T> klazz) {
        Field[] fields = klazz.getDeclaredFields();
        System.out.printf("%d fields:%n", fields.length);
        for (Field field : fields) {
            System.out.printf("%s %s %s%n",
                Modifier.toString(field.getModifiers()),
                field.getType().getSimpleName(),
                field.getName()
            );
        }
    }
}

字符串
上面的代码片段使用反射检查class String的所有声明字段;它生成以下输出:

7 fields:
private final char[] value
private final int offset
private final int count
private int hash
private static final long serialVersionUID
private static final ObjectStreamField[] serialPersistentFields
public static final Comparator CASE_INSENSITIVE_ORDER

有效的Java第2版,第53项:优先使用接口而不是反射

以下是该书的节选:
给定一个Class对象,你可以获得ConstructorMethodField示例,这些示例代表了类的构造函数、方法和字段。[它们]让你可以 * 反射性地 * 操作它们的底层对应对象。然而,这种能力是有代价的:

  • 您将失去编译时检查的所有优点。
  • 执行反射访问所需的代码笨拙且冗长。
  • 性能会受到影响。

作为一条规则,在运行时的正常应用程序中不应反射访问对象。
有一些复杂的应用程序需要反射。例子包括 [...故意省略...] 如果你对你的应用程序是否福尔斯这些类别有任何疑问,它可能不属于。

gpfsuwkq

gpfsuwkq2#

在java中直接调用字段并不是一种好的方式。我建议为bean的字段创建getter和setter方法,然后使用java.beans包中的Introspector和BeanInfo类。

MyBean bean = new MyBean();
BeanInfo beanInfo = Introspector.getBeanInfo(MyBean.class);
for (PropertyDescriptor propertyDesc : beanInfo.getPropertyDescriptors()) {
    String propertyName = propertyDesc.getName();
    Object value = propertyDesc.getReadMethod().invoke(bean);
}

字符串

wkyowqbh

wkyowqbh3#

如果你的类符合JavaBeans规范,我同意Jörn的回答,如果不符合,你使用Spring,这里有一个很好的替代方案。
Spring有一个名为ReflectionUtils的类,它提供了一些非常强大的功能,包括doWithFields(class,callback),这是一个访问者风格的方法,可以让你使用回调对象来覆盖classes字段,如下所示:

public void analyze(Object obj){
    ReflectionUtils.doWithFields(obj.getClass(), field -> {

        System.out.println("Field name: " + field.getName());
        field.setAccessible(true);
        System.out.println("Field value: "+ field.get(obj));

    });
}

字符串
但是这里有一个警告:这个类被标记为“仅供内部使用”,如果你问我的话,这是一个遗憾

67up9zun

67up9zun4#

简单的方法来覆盖类字段并从对象中获取值:

Class<?> c = obj.getClass();
 Field[] fields = c.getDeclaredFields();
 Map<String, Object> temp = new HashMap<String, Object>();

 for( Field field : fields ){
      try {
           temp.put(field.getName().toString(), field.get(obj));
      } catch (IllegalArgumentException e1) {
      } catch (IllegalAccessException e1) {
      }
 }

字符串

z31licg0

z31licg05#

Java有反射(java.reflection.*),但我建议使用Apache Beanutils这样的库,它会比直接使用反射减少很多麻烦。

f4t66c6m

f4t66c6m6#

这里有一个解决方案,它将属性按顺序排序,并将它们与它们的值一起打印出来:

public void logProperties() throws IllegalArgumentException, IllegalAccessException {
  Class<?> aClass = this.getClass();
  Field[] declaredFields = aClass.getDeclaredFields();
  Map<String, String> logEntries = new HashMap<>();

  for (Field field : declaredFields) {
    field.setAccessible(true);

    Object[] arguments = new Object[]{
      field.getName(),
      field.getType().getSimpleName(),
      String.valueOf(field.get(this))
    };

    String template = "- Property: {0} (Type: {1}, Value: {2})";
    String logMessage = System.getProperty("line.separator")
            + MessageFormat.format(template, arguments);

    logEntries.put(field.getName(), logMessage);
  }

  SortedSet<String> sortedLog = new TreeSet<>(logEntries.keySet());

  StringBuilder sb = new StringBuilder("Class properties:");

  Iterator<String> it = sortedLog.iterator();
  while (it.hasNext()) {
    String key = it.next();
    sb.append(logEntries.get(key));
  }

  System.out.println(sb.toString());
}

字符串

x6yk4ghg

x6yk4ghg7#

可以使用pojo-analyzers,它也可以访问字段的getter和setter(没有反射)。

@DetailedPojo
public class ClassWithStuff {
    public String someString;
    //many more fields
}
...
ClassWithStuff classWithStuff = new ClassWithStuff("myString");
// Pojo Analyzers will automatically create a class named DetailedClassWithStuff
DetailedClassWithStuff.list.stream()
    .forEach(fieldDetails -> 
            System.out.println(fieldDetails.getFieldValue(classWithStuff)); // "myString"

字符串
该库使用注解处理,因此不涉及反射-这是最快的解决方案。

相关问题