Джава:Получение свойств класса для построения строкового представления

StackOverflow https://stackoverflow.com/questions/1780896

Вопрос

Допустим, у меня есть такой класс (а также предположим, что все частные переменные:

public class Item {
    private String _id = null;
    private String _name = null;
    private String _description = null;

        ...
}

Теперь, если я хочу создать представление этого класса toString(), я бы сделал что-то подобное внутри класса Item:

@Override
public String toString() {
    return (_id + " " + _name + " " + _description);
}

Но что, если внутри класса у меня есть, скажем, 15 частных переменных?Должен ли я писать имя каждой переменной, как это?

В идеале хотелось бы справиться с задачей, перебрав список приватных переменных этого класса и сконструировав строковое представление:

@Override
public String toString() {
    ArrayList<String> members = getClass().getMembers(); //Some method like this
    String string = "";
    for(...)
        string += members[i] + " ";
}

Или, возможно, метод toJSON, мне все равно понадобится доступ к именам этих переменных.Какие-либо предложения?

Это было полезно?

Решение

Вы можете сделать:

@Override
public String toString() {
  StringBuilder sb = new StringBuilder();
  sb.append(getClass().getName());
  sb.append(": ");
  for (Field f : getClass().getDeclaredFields()) {
    sb.append(f.getName());
    sb.append("=");
    sb.append(f.get(this));
    sb.append(", ");
  }
  return sb.toString();
}

Не используйте конкатенацию строк для создания конечного результата из 15 элементов данных, особенно если toString() будут называть много.Фрагментация памяти и накладные расходы могут быть очень высокими.Использовать StringBuilder для создания больших динамических строк.

Обычно я использую свою IDE (IntelliJ) для простого создания toString() методы для меня, а не использовать для этого отражение.

Еще один интересный подход заключается в использовании Аннотация @ToString из Project Lombok:

import lombok.ToString;

@ToString(excludes="id")
public class ToStringExample {
  private static final int STATIC_VAR = 10;
  private String name;
  private Shape shape = new Square(5, 10);
  private String[] tags;
  private int id;

  @ToString(callSuper=true, includeFieldNames=true)
  public static class Square extends Shape {
    private final int width, height;

    public Square(int width, int height) {
      this.width = width;
      this.height = height;
    }
  }
}

Я нахожу это гораздо более предпочтительным, чем, скажем, сборщики строк toString из Jakarta Commons, потому что этот подход гораздо более настраиваемый и также создается во время компиляции, а не во время выполнения.

Другие советы

Проверьте этот API org.apache.commons.lang.builder.ToStringBuilder, он предоставляет несколько способов создания toString с отражением или без отражения.Обратите внимание и на другие подклассы.

Есть такое апи, и оно называется Java-отражение

Чтобы выполнить то, что вы запрашиваете, вы можете просто сделать что-то вроде:

 Class<?> cls = this.getClass();
 Field fieldlist[] = cls.getDeclaredFields();
 for (Field aFieldlist : fieldlist) {
   // build toString output with StringBuilder()
 }

Это должно быть именно то, что вы ищете

    public String toString() {
    StringBuilder sb = new StringBuilder();
    try {
        Class c = Class.forName(this.getClass().getName());
        Method m[] = c.getDeclaredMethods();
        Object oo;

        for (int i = 0; i < m.length; i++)
            if (m[i].getName().startsWith("get")) {
                oo = m[i].invoke(this, null);
                sb.append(m[i].getName().substring(3) + ":"
                        + String.valueOf(oo) + "\n");
            }
    } catch (Throwable e) {
        System.err.println(e);
    }
    return sb.toString();
}

Большинство IDE предоставляют способ создания toString метод в данном классе.

Учитывая Item класс с несколькими полями:

class Item {
    int i;
    int j;
    int k;
    int l;
    int m;
    int n;
    int o;  
}

Например, в Eclipse выполнение функции «Создать toString()» в Item класс выше создаст следующее:

@Override
public String toString() {
    return "Item [i=" + i + ", j=" + j + ", k=" + k + ", l=" + l + ", m="
            + m + ", n=" + n + ", o=" + o + "]";
}

С использованием отражение позволит программным способом наблюдать за собственными полями, но само отражение является довольно дорогостоящим (читай:медленный) процесс, поэтому, если это действительно не требуется, используя фиксированную toStringметод, написанный во время выполнения, вероятно, будет более желательным.

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

Начиная с хороший медицинский ответ, вы можете использовать этот код для строкового представления всех полей объекта, даже если ты не из его класса (очевидно, это только для полей с методом получения):

/**Gives a string representation of the fields of the object
 * @param obj the object
 * @return
 */
private static String objectToString(Object obj) {
    StringBuilder sb = new StringBuilder();
    try {
        Class c = Class.forName(obj.getClass().getName());
        Method m[] = c.getDeclaredMethods();

        Object oo;
        for (int i = 0; i < m.length; i++)
            if (m[i].getName().startsWith("get")) {
                oo = m[i].invoke(obj, null);
                sb.append(m[i].getName().substring(3) + "="
                        + String.valueOf(oo) + "\n");
            }
    } catch (Throwable e) {
        System.err.println(e);
    }
    return sb.toString();
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top