2

关于我要实现的目标的一点背景:

我正在解析 JSON(超过 15GB),我必须将其存储在内存中,因此不欢迎任何包装器和额外数据,由于其中使用的框架和接口,我必须提供按名称访问字段的功能。通过用 Enum 替换一些 String,用 int 替换 Integer,用 double 替换 Double 等。我能够减少大约 90% 的内存占用(与 Jackson 相比)。

我希望在运行时通过它们的名称有效地访问 Java 中的字段。我知道反射,但就我而言,它的性能根本无法接受,所以我不想使用它。

如果它使问题更容易解决,我不会太在意设置字段值。我在编译时也知道支持字段的名称。

由于盒装对象的内存占用,我不想将所有内容存储在地图Map<String,Object>中,但我不介意以盒装形式返回它们。

我确信其他人也遇到过这个问题,我对任何聪明的解决方案都很感兴趣——比大量的 if ... else ... 语句更聪明。

假设要实现的接口是:

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

get 返回的Object可以是任何类型,包括枚举。一个天真的实现是:

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

您想要的是从 afieldName到值的映射,其类型由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/

“高性能原始集合 (HPPC) 库为所有 Java 原始类型(字节、整数等)提供典型的数据结构(列表、堆栈、映射)模板生成,以节省内存并提高性能。”

特别是, 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... 
}

请注意,他们有自己特殊的lget()方法调用来优化 containsKey() / get() 使用模式,这种模式在地图中非常典型。

于 2012-07-30T23:24:37.787 回答