2

私が達成しようとしていることについての少しの背景:

JSON (15GB 以上) を解析していますが、それをメモリに保存する必要があるため、ラッパーや余分なデータは歓迎されません。その中で使用されるフレームワークとインターフェイスのために、名前でフィールドにアクセスする機能を提供する必要があります。一部の String を Enum に、Integer を int に、Double を double になどに置き換えることで、(Jackson と比較して) メモリ フットプリントの約 90% を削減できます。

Javaの実行時に名前でフィールドに効率的にアクセスしたいと考えています。私はリフレクションを認識していますが、私の場合、そのパフォーマンスは単に受け入れられないため、使用したくありません。

問題の解決が容易になる場合は、フィールド値の設定についてあまり気にしません。また、コンパイル時に、サポートされているフィールドの名前も知っています。

ボックス化されたオブジェクトのメモリフットプリントのために、すべてをマップに保存したくありませんMap<String,Object>が、それらをボックス化された形式で返すことは気にしません。

この問題は他の人が遭遇したと確信しており、賢い解決策に興味があります-大量の if ... else ... ステートメントよりも賢いです。

実装するインターフェースは次のとおりです。

public interface Accessor {
    Object get(String fieldName);
}

get によって返される値はObject、enum を含む任意の型にすることができます。単純な実装は次のようになります。

public class TestObject implements Accessor {

    public enum MyEnum {ONE, TWO, THREE};

    private final MyEnum myEnum;
    private final int myInt;
    private final double myDouble;
    private final String myString;

    public TestObject(MyEnum myEnum, int myInt, double myDouble, String myString) {
        this.myEnum = myEnum;
        this.myInt = myInt;
        this.myDouble = myDouble;
        this.myString = myString;
    }

    @Override
    public Object get(String fieldName) {
        if ("myEnum".equals(fieldName)) {
            return myEnum;
        } else if ("myInt".equals(fieldName)) {
            return myInt;
        } else if ("myDouble".equals(fieldName)) {
            return myDouble;
        } else if ("myString".equals(fieldName)) {
            return myString;
        } else {
            throw new UnsupportedOperationException(); // Or could simply return null
        }
    }

}
4

2 に答える 2

4

必要なのは、からfieldName値へのマッピングであり、そのタイプはによって決定されますfieldName。フィールド名のセットは事前にわかっているので、これはEnum.

各フィールドを列挙型としてハードコーディングするという考えが気に入らない場合、バリエーションは型ごとの列挙型 (MY_FIELD1 が MY_ENUM になる) であり、fieldName からこの EnumType へのマッピングがあります。

以下のコードでは、fieldName と TestObject の関係について仮定しています。具体的には、フィールド名ごとに個別の値ではなく、TestObject が同じ値のさまざまなタイプを提示しているように見えます (確かに妥当な場合)。

したがって、コードに:


リライト:

@Override
public Object get(String fieldName) {
    MyField field = MyField.mapNameToField(fieldName);
    if (field == null)
        throw new UnsupportedOperationException(); // Or could simply return null
    return field.getValue(this);
}

与えられた(のようなもの):

enum MyField {
  MY_FIELD1("myField1") {
      public Object getValue(TestObject obj) { return obj.myEnum; }
  },
  MY_FIELD2("myField2") {
      public Object getValue(TestObject obj) { return obj.myInt; }
  },
  ...
  ;

  public abstract Object getValue(TestObject obj);
  public String getName() { return name; }

  public static MyField mapNameToField(String name) { return map.get(name); }

  static {
      map = new HashMap<String,MyField>();
      for(MyField value: values()) {
          map.put(value.getName(), value);
      }
  }

  private MyField(String fieldName) { name = fieldName; }

  private String name;
  private static Map<String, MyField> map;
}
于 2012-07-30T22:51:49.193 に答える
0

私はこれを使用したことはありませんが、有望に見えます:

http://labs.carrotsearch.com/download/hppc/0.4.1/api/

「High Performance Primitive Collections (HPPC) ライブラリは、すべての Java プリミティブ型 (byte、int など) に対してテンプレート生成された典型的なデータ構造 (リスト、スタック、マップ) を提供し、メモリを節約してパフォーマンスを向上させます。」

特に、 Object{Type}OpenHashMap クラスが探しているものかもしれません:

  1. ObjectByteOpenHashMap
  2. ObjectCharOpenHashMap
  3. ObjectDoubleOpenHashMap
  4. ObjectFloatOpenHashMap
  5. ObjectIntOpenHashMap
  6. ObjectLongOpenHashMap
  7. ObjectShortOpenHashMap

これらの 7 つすべてをフィールド (または任意のサブセット) として定義し、それぞれを順番に調べて、そのタイプのプリミティブ値のキーが存在するかどうかを確認するとします。例えば、

if (byteMap.containsKey(key)) {
  return byteMap.lget(); // last value saved in a call to containsKey()
} else if (charMap.containsKey(key)) {
  return charMap.lget();
} else if {
  // and so on... 
}

マップで典型的な containsKey() / get() 使用パターンを最適化するために、独自の特別なlget()メソッド呼び出しがあることに注意してください。

于 2012-07-30T23:24:37.787 に答える