我有一个Java数据结构,这是通过反序列化这个JSON产生的:
{
'level1 value1': {
'level2 value1': {
'level3 value1': [ "25", "45", "78" ],
// ...
'level3 valueN': [ "59", "17", "42" ]
},
// ...
'level2 valueN': {
'level3 value1': [ "34", "89", "54" ],
// ...
'level3 valueN': [ "45", "23", "23" ]
},
},
// ...
'level1 valueN': {
// ...
}
}
在Java中,这变为:
Map<String, Map<String, Map<String, List<String>>>> data;
当然,级别的数量是任意的,所以我无法在变量声明中嵌套集合。我正在做的是:
void traverse(Map<String, ?> children) {
for (Map.Entry<String, ?> node : data.entrySet()) {
if (node.getValue() instanceof Map) {
doSomethingWithNonLeafNode((Map<String, Map<String, ?>>) node);
} else if (node.getValue() instanceof List) {
doSomethingWithLeafNode((Map <String, List<String>>) node);
}
}
}
void doSomethingWithNonLeafNode(Map <String, Map<String ?>> node) {
// do stuff
}
void doSomethingWithLeafNode(Map <String, List<String>> node) {
// do stuff
}
这显然是a)使用了一些未经检查的演员,而b)是丑陋的。我尝试定义新类型来解决这个问题:
private interface Node extends Map<String, Map<String, ?>> {
}
private interface LeafNode extends Map<String, List<String>> {
}
// ...
if (node.getValue() instanceof Map) {
doSomethingWithNonLeafNode((Node) node);
} else if (node.getValue() instanceof List) {
doSomethingWithLeafNode((LeafNode) node);
}
但是,这给了我一个运行时异常:
java.lang.ClassCastException: java.util.HashMap cannot be cast to com.foo.ReportDataProcessor$Node
我怎样才能以干净,无警告的方式做到这一点?
答案 0 :(得分:1)
定义新类型对您没有帮助,因为JSON解串器不了解您的Node&amp; LeafNode接口,因此生成的具体集合对象无法实现它们。
由于您事先并未实际了解地图的元素类型,因此不需要强制执行编译时类型安全性:您只能依赖运行时类型检查。因此,仿制药只会使您的生活变得复杂并使您的代码变得更加丑陋,但并不会给您带来任何好处。
所以我认为这里最差的解决方案是删除泛型,在代码中使用非泛型Map
和List
类型。
答案 1 :(得分:1)
如果没有联合类型,我认为你不能很好地做到这一点。
如果您考虑一下,您正在处理的Map
实际上可以包含两种类型的对象 - 下面级别的另一个映射,或者叶子节点的字符串列表。因此,此映射的通用参数必须是映射和列表的一些常见超类型。最后,当您检测到您有一个叶节点并正在处理列表时,您将 进行投射。
答案 2 :(得分:1)
为了更清洁的解决方案,您可能会忘记Map作为容器并创建一个对象来表示树,更好
public class Node{
String text;
List<String> data;
List<Node> children;
}
您可以使用Map实现当前使用Map填充树的方法。如果Node的子项不为空,那么您不必考虑数据。
void traverse(Node node) {
if(node.getChildren()!=null){
doSomethingWithNonLeafNode(node);
// Or for recursion if you need
// List<Node> children=node.getChildren();
// for(Node c:children){
// traverse(c);
// }
}else{
doSomethingWithLeafNode(node);
}
}