web-dev-qa-db-ja.com

Javaでクラス属性をループする方法は?

Javaのクラス属性を動的にループするにはどうすればよいですか。

例えば:

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

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

これはJavaで可能ですか?

73
Zakaria

あなたが求めていることをするための言語的サポートはありません。

リフレクションを使用して、実行時に型のメンバーにリフレクションでアクセスできます(たとえば 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

Effective Java 2nd Edition、Item 53:インターフェースをリフレクションに優先させる

これらは本からの抜粋です:

Class オブジェクトを指定すると、 ConstructorMethod 、および Field コンストラクター、メソッド、およびフィールドを表すインスタンスを取得できますクラスの。 [それら]は、それらの基礎となる対応物を反射的に操作することができます。ただし、このパワーには代償が伴います。

  • コンパイル時チェックの利点をすべて失います。
  • リフレクティブアクセスを実行するために必要なコードは不器用で冗長です。
  • パフォーマンスが低下します。

原則として、通常のアプリケーションでは、実行時にオブジェクトに反射的にアクセスしないでください。

リフレクションを必要とする洗練されたアプリケーションがいくつかあります。例には、[...意図的に省略...]アプリケーションがこれらのカテゴリのいずれかに該当するかどうか疑問がある場合は、おそらくしません。

89

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);
}
41
Jörn Horstmann

Jörn's answer に同意しますが、クラスがJavaBeabs仕様に準拠している場合は、そうではなく、Springを使用している場合に適した代替手段です。

Springには ReflectionUtils という名前のクラスがあります。これは doWithFields(class、callback) を含むいくつかの非常に強力な機能を提供します。このようなコールバックオブジェクト:

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

    });
}

ただし、警告があります。クラスには「内部使用のみ」というラベルが付けられています。

16

クラスフィールドを反復処理し、オブジェクトから値を取得する簡単な方法:

 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) {
      }
 }
12
Rickey

Javaにはリフレクション(Java.reflection。*)がありますが、Apache Beanutilsのようなライブラリを調べることをお勧めします。これにより、リフレクションを直接使用するよりもはるかに簡単になります。

6

Java Reflections APIを使用して、クラス属性を動的にループできます。

for (Field field : objClass.getDeclaredFields()) {
            // Invoke the getter method on the Institution1 object.
            Object objField = new PropertyDescriptor(field.getName(),
                    Institute1.class).getReadMethod().invoke(inst1);
2
Rehan

以下に、プロパティをアルファベット順に並べ替え、それらをすべて値とともに出力するソリューションを示します。

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