关于我正在努力实现的目标的一些背景:
我正在解析JSON(超过15GB)并且我必须将它存储在内存中,因此不欢迎任何包装器和额外数据,因为其中使用的框架和接口我必须提供按名称访问字段的功能。通过用Enum替换一些String,用int替换一个Integer,用double替换Double等。我能够减少大约90%的内存占用(与Jackson相比)。
我希望通过Java名称在Java运行时有效地访问这些字段。我知道反思,但就我的情况而言,它的表现是不可接受的,所以我不想使用它。
如果它使问题更容易解决,我对设置字段值不太感兴趣。我还在编译时知道支持字段的名称。
由于盒装对象的内存占用,我不想将所有内容存储在地图中,即Map<String,Object>
,但我不介意以盒装形式返回它们。
我确信其他人遇到了这个问题,而且我对任何聪明的解决方案感兴趣 - 比if ...其他......陈述更聪明。
假设要实现的接口是:
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
}
}
}
答案 0 :(得分: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;
}
答案 1 :(得分:0)
我从未使用过这个,但看起来很有希望:
http://labs.carrotsearch.com/download/hppc/0.4.1/api/
“高性能基元集合(HPPC)库提供了为所有Java基元类型(字节,整数等)模板生成的典型数据结构(列表,堆栈,映射),以节省内存并提高性能。”
特别是,Object {Type} OpenHashMap类可能正是您所需要的:
我想你会将所有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()使用模式,这对于地图来说是典型的。