什么是最适合表示JSON的Java数据结构?

4
我正在开发一个RESTful Android移动客户端,我的应用程序和服务器之间的信息交换是通过JSON进行的。因此,我现在有点困惑要选择哪种数据结构来表示JSON响应和数据,因为有很多选择。我只是选择了LinkedHashMap<>,但据我所知,JSON是无序的。在互联网上,我看到人们使用Map<>或HashMap<>来处理这个问题。所以问题是 - 什么是最好的数据结构来处理这个目的?如果没有明确的答案,那么使用我提到的数据结构的优缺点是什么?

1
JSON是“对象”、“数组”和基本类型的混合。大部分情况下,Map的一种变体适用于“对象”,而ArrayList适用于数组。但是,在Java中的许多JSON实现都提供了它们自己的类(出于好坏原因)。 - Hot Licks
2
从概念上讲,你很难找到任何无法将任何JSON输入反序列化为Map<String, Object>的JSON库。 Object值可以是自动装箱的原始类型之一,列表或另一个映射。虽然不一定是最容易处理的数据结构 - 我强烈建议使用POJO构建真正的对象模型。 - Perception
我建议使用一个库将JSON反序列化为POJOs。Gson在Android上表现很好。 - Luke
5个回答

5
我不同意第一个答案。REST范式的开发是为了让您操作对象,而不是操作。
对我来说,最明智的方法是在客户端声明bean并解析json响应和请求。我建议使用GSON库进行序列化/反序列化。JsonObject/ JsonArray几乎从未是最佳选择。
也许如果您提供要使用的操作示例,我们可能能够更精确地帮助您。
编辑:让我也给出一些GSON示例。让我们使用这个线程来比较不同的库。
在大多数情况下,REST服务通信对象。假设您发布一个产品,它引用商店。
{ "name": "Bread",
  "price": 0.78,
  "produced": "08-12-2012 14:34",
  "shop": {
     "name": "neighbourhood bakery"
  }
}

然后如果您声明以下bean:

public class Product {
    private String name;
    private double price;
    private Date produced;
    private Shop shop;
    // Optional Getters and setters. GSON uses reflection, it doesn't need them
    // However, better declare them so that you can access the fields
}

public class Shop {
   private String name;
    // Optional Getters and setters. GSON uses reflection, it doesn't need them
    // However, better declare them so that you can access the fields
}

您可以使用以下方式反序列化json:
String jsonString; // initialized as you can
GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.setDateFormat("MM-dd-yyyy HH:mm"); // setting custom date format
Gson gson = gsonBuilder.create();
Product product = gson.fromJson(jsonString, Product.class);
// Do whatever you want with the object it has its fields loaded from the json

另一方面,您甚至可以更轻松地将其序列化为json:
GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.setDateFormat("MM-dd-yyyy HH:mm"); // setting custom date format
Gson gson = gsonBuilder.create();
String jsonString = gson.toJson(product);

2
你是在谈论如何从服务器请求中接收和解析JSON字符串吗?针对此情况,你可以使用以下方法:
import org.json.JSONArray;
import org.json.JSONObject;

我使用这些工具,读取了来自POST请求的JSON数组并将其结果信息存储在我的项目中的类对象中。

对于JSONArray中的每个项,您可以像这样提取JSONObject和属性:

for (int i = 0; i < jsonArray.length(); i++) {
    JSONObject jsonObject = jsonArray.getJSONObject(i);
    jsonObject.getString("text");
}

就数据的实际存储而言,如上所述,JSON数据可能因来源不同而采用各种格式,因此通常在客户端进行解析,并保存在应用程序类对象中供使用。或者更通用地,您可以使用Map<String, Object>来存储数据。


1
这是我见过的最好的答案:

https://dzone.com/articles/which-is-the-right-java-abstraction-for-json

总结:有三种抽象类型:pojos(简单的Java对象)、maps(映射)和lists(列表),以及用于表示对象、数组和基本类型的自定义类。每种类型都有优缺点,没有明显的胜者。
Pojos具有最大的优势,但并不总是可以使用它们。如果可以,请使用它们,如果必须使用其他类型。

0

我已经使用xstream以以下方式序列化JSON

XStream xstream = new XStream(new JsonHierarchicalStreamDriver());
xstream.setMode(XStream.NO_REFERENCES);
xstream.alias("myAlias", MyClass.class); // requires a no argument constructor
System.out.println(xstream.toXML(product));     

好的,评论区的先生想要一个反序列化的例子,这里给您:

XStream xstream = new XStream(new JsonHierarchicalStreamDriver());
xstream.alias("myAlias", MyClass.class);
Product product = (Product)xstream.fromXML(json);
System.out.println(product.getName());

如果您需要进一步的帮助,请告诉我...


那么XStream在做什么:将Bean序列化为/从json字符串?它需要任何额外的注释或其他东西吗?它能处理嵌套的Beans吗?它能在Android上工作吗?我问这个问题是因为我以前没有听说过这个库。 - Boris Strandjev
答案中提到的教程涵盖了这些内容。简而言之,是的,不,是的和是的。 - hd1
我已经扩展了我的答案,包括我建议的库的使用示例。您是否介意也扩展一下您的答案?我知道您指向教程,但简短的示例也可能有用。如果我们这样做,我希望我们能增加答案的价值。 - Boris Strandjev
@BorisStrandjev 如果你看了教程,就会找到你的示例代码,但我同样很懒,因此我已经复制粘贴了上面的代码。 - hd1
为什么要使用 XmlJsonHierarchicalStreamDriver 是什么?还有哪些模式? - Boris Strandjev
显示剩余2条评论

0

如果你不是在进行最简单的映射操作,那么你应该使用完整的类结构。按照 JSON 数据结构创建你的类层次结构,并使用Jackson将 JSON 直接映射到类层次结构中,使用 ObjectMapper。

通过这种解决方案,你不需要将 Object 强制转换为 Map,也不需要使用 JSONObject 或 JSONArray 进行操作,也不需要在代码中进行多级 Map 遍历。你只需将 JSON 字符串传递给 ObjectMapper,然后获取一个包含子对象(甚至集合)的 Object,ObjectMapper 会自动映射它们。


所以...根据你回答中的示例(和教程),你正在将反序列化到一个Product而不是Map或类似的东西,这正是我在类层次结构方面所提到的。你有一些包括Product类(以及Product使用的任何类)的类层次结构,因此你的答案与我的相同,只是使用了不同的工具。 - digitaljoel
1
是的,我们有三个类似的工具和一个不同的答案(我认为最不合适)。如果我必须进行比较,我会说Gson比Jackson更快且更易于使用。一个区别是Jackson默认使用getter/setter,而Gson使用反射。我想知道@hd1的工具情况如何? - Boris Strandjev
1
我们实际进行了一些性能测试,并发现jackson比gson快得多。我们的json更大(600k+),因此对于小响应它们可能非常相似。我们首先选择了gson,当转换为jackson时,它几乎是一个插入式替换,它们都同样易于使用,并且比JSONObject容易使用数个数量级。 - digitaljoel

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接