web-dev-qa-db-fra.com

Java: Obtenir les propriétés d'une classe pour construire une représentation à chaîne

Disons que j'ai une classe comme celle-ci (et supposons également que toutes les variables privées:

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

        ...
}

Maintenant, si je veux construire une représentation de Tostring () de cette classe, je ferais quelque chose comme celui-ci à l'intérieur de la classe d'articles:

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

Mais que se passe-t-il si je dis 15 variables privées à l'intérieur de la classe? Dois-je écrire le nom de chaque variable comme celle-ci?

Idéalement, je voudrais obtenir la tâche en itérant dans la liste des variables privées de cette classe et de construire la représentation de chaîne:

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

Ou peut-être une méthode Tojson, j'aurais toujours besoin d'un accès aux noms de ces variables. Aucune suggestion?

21
Legend

Vous pourriez faire:

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

Ne pas Utilisez la concaténation de la chaîne pour construire un résultat final de 15 membres de données, en particulier si la fonction toString() sera appelée beaucoup. La fragmentation de la mémoire et les frais généraux peuvent être vraiment élevés. Utilisez StringBuilder pour la construction de grandes chaînes dynamiques.

Je reçois habituellement mon IDE (Intellij) pour générer simplement toString() méthodes pour moi plutôt que d'utiliser la réflexion pour cela.

Une autre approche intéressante consiste à utiliser l'annotation @ Tostring Annotation du projet 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;
    }
  }
}

Je trouve cela beaucoup plus préférable à, disons, les constructeurs de Jakarta Commons Tostring, car cette approche est beaucoup plus configurable et elle est également construite à la compilée, pas de temps d'exécution.

35
cletus

Vérifiez cette API org.apache.commons.lang.builder.tostringbuilder , il fournit plusieurs façons de créer une réflexion Usinf ou sans réfléchir. Jetez un coup d'œil à d'autres sous-classes aussi.

8
Bhushan Bhangale

Il y a une telle API, et elle s'appelle réflexion Java

Pour accomplir ce que vous demandez, vous pouvez simplement faire quelque chose comme:

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

Cela devrait être exactement ce que vous recherchez

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

La plupart des IDes fournissent un moyen de créer une méthode toString dans une classe donnée.

Étant donné une classe Item avec plusieurs champs:

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

Par exemple, dans Eclipse, la fonction "Générer" ToString () "sur la classe Item ci-dessus créera ce qui suit:

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

Utilisation - réflexion permettrait à une manière programmatique d'observer ses propres champs, mais la réflexion elle-même est une procédure assez coûteuse (lue: lente), donc à moins que cela ne soit vraiment requis, à l'aide d'un toStringmethod Écrit au moment de l'exécution va probablement être plus souhaitable.

2
coobird