5

クラスが任意の (ただし固定の) 数の異なる型の変数で構成され、それらの変数を反復処理し、コードでそれらの名前を使用したいという状況がいくつかあります。各関数で各変数名を再入力するよりもスマートな方法はありますか?

私の最初の考えは、HashMap を使用してローカル変数を格納することですが、それは非効率的で、複数の型を処理できません。

以下のコードは、必要な読み取りを短縮するためにシミュレートされていますが、通常は 3 つ以上の変数です。

class Widget implements Parcelable {
    String name, code;
    Long price;

    public void writeToParcel(Parcel dest, int flags) {
        dest.writeString(name);
        dest.writeString(code);
        dest.writeLong(price);
    }

    public Widget(Parcel o) {
        name = o.name;
        code = o.code;
        price = o.price;
    }

    public String getXML() {
        return "<Widget><name>"+name+"</name><code>"+code
              +"</code><price>"+price+"</price></Widget>";
    }
}

代わりに、(疑似コード)のようなことをしたいと思います:

public Widget(Parcel o) {
    for (Map<Name,Data> item: o.getMap()) {
        this.setValue(Name, Data);
    }
}
public String getXML() {
    StringBuilder XML = new StringBuilder();
    XML.append("<Widget>");
    for (Map<Name,Data> item: o.getMap()) {
        XML.append("<"+Name+">" + Data + "</"+Name+">");
    }
    XML.append("</Widget>");
    return XML.toString();
}

この種のことを行うためのパターンがあるに違いないと私は考え続けていますが、それは私の Java の経験を蹴散らした私の Python の歴史に過ぎないのかもしれません。

更新: これは、メンバー変数から XML をフェッチするだけではなく、複数のメンバー関数でメンバー変数をループすることに関するものです。私のレパートリーには、Java のリフレクション機能が欠けているようです。

私の新しい小さなコンストラクターは、何か役に立つことを学べたことを嬉しく思います。

public Widget(Widget other) {
    for (Field f : getClass().getDeclaredFields()) {
        if (f.getName() == "TAG") {
            continue;
        }
        f.set(this, f.get(other));
    }
}
4

4 に答える 4

13

これは通常、リフレクションで解決されます。

for (Field f : getClass().getDeclaredFields()) {
    String name = f.getName();
    String value = f.get(this);
}

ただし、XML への書き込みや XML からの読み取りには、車輪を再発明するよりも、おそらくJAXBを使用したいでしょう。

于 2012-11-29T20:21:48.077 に答える
3

ジャクソンを使う:

https://github.com/FasterXML/jackson-dataformat-xml

シリアル化は、JSON シリアル化と非常によく似ています。変更する必要があるのは、使用する ObjectMapper インスタンスだけです。

// Important: create XmlMapper; it will use proper factories, workarounds
ObjectMapper xmlMapper = new XmlMapper();
String xml = xmlMapper.writeValue(new Simple());

POJO を使用すると、次のようになります。

public class Simple {
    public int x = 1;
    public int y = 2;
}

あなたは次のようなものを得るでしょう:

<Simple>
  <x>1</x>
  <y>2</y>
</Simple>

(ただし、デフォルトでは出力はインデントされません: 標準の Jackson メカニズムを使用してインデントを有効にすることができます)

XML からの POJO の逆シリアル化 シリアル化と同様に、逆シリアル化は JSON の逆シリアル化と大差ありません。

ObjectMapper xmlMapper = new XmlMapper();
Simple value = xmlMapper
   .readValue("<Simple><x>1</x><y>2</y></Simple>", Simple.class);

PSそのためにリフレクションを使用し、 を使用して宣言されたすべてのフィールドを反復処理することもできますClass.getDeclaredFields()。しかし、私の経験から、そうしなければならないことはめったにありません。さまざまな目的のために多くのサードパーティのオープンソース ライブラリがあり、通常はそれらを使用するだけの方が適切なソリューションです (たとえば、この特定のケースでは Jackson)。

于 2012-11-29T20:24:34.660 に答える
2

コードが同じパターンに従うクラスが多数ある場合は、ある種の定義ファイルからJavaソースコードを生成するコードジェネレーターを作成します。次に、ジェネレーターに最初の例のような単純なコードを作成させることができます。これは、(一般的なマップやリフレクションなどを使用するよりも)読みやすく理解しやすいものです。定義ファイルは、各種類のオブジェクトのフィールドの「公式」ソースになります。

すでにPythonに精通しているので、定義ファイルをPythonスクリプトに直接組み込んで、ソースコードを作成することができます。例えば:

Objects = {
    "Widget": [
        (TYPE_STRING, "name"),
        (TYPE_STRING, "code"),
        (TYPE_LONG, "price"),
    ],
    # ...
}

などの適切な定義がTYPE_STRINGあれば、これからJavaソースを生成するコードを書くのは簡単なはずです。

于 2012-11-29T20:20:49.527 に答える
0

XStreamはこれを行うための最も単純なフレームワークだと思います2 分間のチュートリアルを参照すると、アイデアが得られます。

マッピング クラスを作成するのと同じくらい簡単です。たとえばWidget、すべてのメンバー属性と可能なオブジェクトのネストを使用して、次を呼び出します。

   XStream xstream = new XStream(new DomDriver());
   String xml = xstream.toXML(widgetObject);  // <-- Get XML String from object

   Widget widget = (Widget)xstream.fromXML(xml); //<-- Get object from XML
于 2012-11-29T20:25:26.973 に答える