Как зациклить атрибуты класса в Java? - PullRequest
70 голосов
/ 26 июля 2010

Как можно динамически перебирать атрибуты класса в Java.

Например:

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

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

возможно ли это в Java?

Ответы [ 6 ]

87 голосов
/ 26 июля 2010

Нет лингвистической поддержки, чтобы делать то, что вы просите.

Вы можете рефлексивно обращаться к членам типа во время выполнения, используя отражение (например, с помощью 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, вы можете получить Constructor, Method и Field экземпляров представляющие конструкторы, методы и поля класса. [Они] позволяют вам манипулировать их основными аналогами рефлексивно . Эта сила, однако, имеет цену:

  • Вы теряете все преимущества проверки во время компиляции.
  • Код, необходимый для выполнения отражательного доступа, является неуклюжим и многословным.
  • Производительность страдает.

Как правило, объекты не должны отражаться в обычных приложениях во время выполнения.

Есть несколько сложных приложений, которые требуют отражения. Примеры включают [... специально пропущено ...] Если у вас есть какие-либо сомнения относительно того, попадает ли ваше приложение в одну из этих категорий, оно, вероятно, не соответствует.

40 голосов
/ 26 июля 2010

Прямой доступ к полям не очень хороший стиль в Java. Я бы предложил создать методы getter и setter для полей вашего компонента, а затем использовать затем классы Introspector и BeanInfo из пакета java.beans.

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);
}
16 голосов
/ 26 июля 2010

Хотя я согласен с ответом Йорна , если ваш класс соответствует спецификации 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));

    });
}

Но вот предупреждение: класс помечен как «только для внутреннего использования», что очень жаль, если вы спросите меня

12 голосов
/ 02 января 2013

Простой способ перебора полей класса и получения значений из объекта:

 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) {
      }
 }
6 голосов
/ 26 июля 2010

В Java есть Reflection (java.reflection. *), Но я бы посоветовал заглянуть в такую ​​библиотеку, как Apache Beanutils, это сделает процесс намного менее сложным, чем прямое отражение.

0 голосов
/ 11 июня 2014

Вот решение, которое сортирует свойства по алфавиту и печатает их все вместе со значениями:

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());
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...