Как перебрать атрибуты класса в 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?

Ответ 1

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

Вы можете отражать элементы типа во время выполнения с помощью отражения (например, 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 2nd Edition, пункт 53: Предпочитает интерфейсы для отражения

Это выдержки из книги:

Учитывая объект Class, вы можете получить Constructor, Method и Field экземпляры, представляющие конструкторы, методы и поля класса. [Они] позволяют вам рефлексивно манипулировать их базовыми аналогами. Эта сила, однако, идет по цене:

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

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

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

Ответ 2

Доступ к полям напрямую не очень хороший стиль в java. Я бы предложил создать методы getter и setter для полей вашего bean, а затем использовать классы 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);
}

Ответ 3

Пока я согласен с ответом Jörn, если ваш класс соответствует спецификации JavaBeabs, вот хорошая альтернатива, если это не так, и вы используете Spring.

Spring имеет класс с именем ReflectionUtils, который предлагает некоторые очень мощные функции, включая doWithFields (класс, обратный вызов), метод стиля посетителя, который позволяет вам перебирать поля классов с помощью объекта обратного вызова следующим образом:

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

    });
}

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

Ответ 4

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

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

Ответ 5

В Java есть Reflection (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);

Ответ 7

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

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