23

このようなクラスがあるとしましょう (さらに、すべてのプライベート変数を次のように仮定します。

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 メソッドで、これらの変数の名前にアクセスする必要があります。助言がありますか?

4

7 に答える 7

37

あなたがすることができます:

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

toString()特にが頻繁に呼び出される場合は、文字列連結を使用して 15 個のデータ メンバーから最終結果を構築しないでください。メモリの断片化とオーバーヘッドが非常に高くなる可能性があります。StringBuilder大きな動的文字列を構築するために使用します。

私は通常、toString()これにリフレクションを使用するのではなく、IDE (IntelliJ) に単にメソッドを生成させます。

もう 1 つの興味深いアプローチは、Project Lombok の @ToString アノテーションを使用することです。

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

このアプローチははるかに構成可能であり、実行時ではなくコンパイル時にもビルドされるため、これは Jakarta Commons toString ビルダーよりもはるかに好ましいと思います。

于 2009-11-23T03:06:20.063 に答える
8

この API org.apache.commons.lang.builder.ToStringBuilderを確認してください。これは、toString をリフレクションを使用して、またはリフレクションなしで作成する複数の方法を提供します。他のサブクラスも見てみましょう。

于 2009-11-23T03:02:45.043 に答える
6

そのようなAPIがあり、 Java Reflectionと呼ばれています

あなたが要求していることを達成するために、あなたは単に次のようなことをすることができます:

 Class<?> cls = this.getClass();
 Field fieldlist[] = cls.getDeclaredFields();
 for (Field aFieldlist : fieldlist) {
   // build toString output with StringBuilder()
 }
于 2009-11-23T03:08:04.687 に答える
4

これはまさにあなたが探しているものでなければなりません

    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();
}
于 2009-11-23T03:21:57.593 に答える
2

toStringほとんどの IDEは、特定のクラスでメソッドを作成する方法を提供します。

複数のフィールドを持つItemクラスの場合:

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

たとえば、Eclipse では、Item上記のクラスで「Generate toString()」機能を実行すると、次のものが作成されます。

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

リフレクションを使用すると、プログラムによって独自のフィールドを監視できますが、リフレクション自体はかなり高価な (読み取り: 遅い) プロセスであるため、本当に必要でない限り、toString実行時に記述された固定メソッドを使用する方がおそらく望ましいでしょう。

于 2009-11-23T03:05:54.510 に答える
1

速度の問題に遭遇する可能性があります。リフレクションを使用している場合、ネイティブ コードを実行する場合と比較して、非常に遅くなる可能性があります。リフレクションを使用する場合は、おそらく反復する変数のメモリ内キャッシュが必要です。

于 2009-11-23T03:07:35.723 に答える
-1

良いmedopalの答えから始めて、このコードを使用して、クラスの外にいる場合でも、オブジェクトのすべてのフィールドの文字列表現を作成できます(明らかに、getterメソッドを持つフィールドのみです)。

/**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();
}
于 2010-12-06T17:01:35.900 に答える