【问题标题】:Arrays containing 10 extra null elements when parsed into POJO with GSON使用 GSON 解析为 POJO 时包含 10 个额外空元素的数组
【发布时间】:2014-08-21 19:22:41
【问题描述】:

我正在从 web api 接收一个 Json 对象,

如下所示:

{"Sites":[{"SiteId":1,"SiteName":"Site 1"},{"SiteId":2,"SiteName":"Site 2"},{"SiteId":3,"SiteName":"Site 3"}]}

现在我有以下代码,它使用 gson 将其解析为 POJO:

@Override
protected Response<T> parseNetworkResponse(NetworkResponse response) {
    try {
        String json = new String(response.data,
                HttpHeaderParser.parseCharset(response.headers));
        return Response.success(gson.fromJson(json, clazz),
                HttpHeaderParser.parseCacheHeaders(response));
    } catch (UnsupportedEncodingException e) {
        return Response.error(new ParseError(e));
    } catch (JsonSyntaxException e) {
        return Response.error(new ParseError(e));
    }
}

这是我的 POJO:

 public class UsersSitesViewModel 
 {
     public List<UserSite> Sites;
 }

public class UserSite {

 public UserSite(int siteId, String siteName) 
 {
    SiteId = siteId;
    SiteName = siteName;
 }

 public int SiteId;
 public String SiteName;
}

但是现在当我在我的代码中运行并调试以查看它创建的 pojo 时:

如下所示:

为什么要在我的数组中插入 10 个 Null 值?

这是不正确的!

【问题讨论】:

  • 那么问题出在哪里?
  • 当您以编程方式解析数组时,您实际上有 12 个元素还是只有 3 个元素?也许只是列表的表示有问题?
  • @user3218114 问题是它创建的列表中有一大堆空值,
  • @Nico 收到的 Json 如问题所示。列表中应该只有 3 项。
  • 它没有。它仅用于缓冲,这意味着分配内存。好吧,别担心。调试器是像你我一样的人:D

标签: java android json gson pojo


【解决方案1】:

您看到十个空值的原因是数组列表的工作方式。数组列表本质上是向量,或者类似数组但会自动调整大小的东西。为了防止围绕向量(和 ArrayLists)的额外内存复制,通常使用额外的内存创建。由于复制内存所花费的时间大于开始分配内存所花费的时间,因此大多数实现只是在开始时分配额外的空间。

我们可以通过 ArrayList 中的 size 属性判断这是发生的。 size 列为3,这是数组列表中正确的元素数。因此,当您查询数组列表的长度时,您会得到3

【讨论】:

  • 官方文档中有关于这种行为的参考吗?
  • @Nico "每个 ArrayList 实例都有一个容量。容量是用于存储列表中元素的数组的大小。它始终至少与列表大小一样大。因为元素是添加到 ArrayList 后,它的容量会自动增长。除了添加元素具有恒定的摊销时间成本这一事实之外,没有指定增长策略的细节。来自docs.oracle.com/javase/7/docs/api/java/util/ArrayList.html
【解决方案2】:

您需要在UserSite 中覆盖toString()

@Override
public String toString() {
  return String.format("siteId = %d, siteName = %s", SiteId, SiteName);
}

此外,您的字段应为private,Java 命名约定为siteIdsiteName。默认情况下,您继承 Object.toString() 和 Javadoc,

toStringObject 的方法返回一个字符串,该字符串由对象作为其实例的类的名称、at 符号字符“@”和哈希码的无符号十六进制表示形式组成。物体。换句话说,这个方法返回一个字符串等于:

getClass().getName() + '@' + Integer.toHexString(hashCode())

【讨论】:

    【解决方案3】:

    对我来说效果很好。

    UsersSitesViewModel data = new Gson().fromJson(json, UsersSitesViewModel.class);
    System.out.println(new GsonBuilder().setPrettyPrinting().create().toJson(data));
    

    要遵循 Java 命名约定,请使用 @SerializedName 注释

    class UsersSitesViewModel {
        @SerializedName("Sites")
        private List<UserSite> sites;
        // getter & setter
    }
    
    class UserSite {
    
        @SerializedName("SiteId")
        private int siteId;
        @SerializedName("SiteName")
        private String siteName;
        // getter & setter
    }
    

    您可以将其转换为 Map&lt;String,Object&gt; 仅用于调试目的

    Type type = new TypeToken<Map<String, Object>>() {}.getType();
    Map<String, Object> data = new Gson().fromJson(json, type);
    

    输出:

    {
      "Sites": [
        {
          "SiteId": 1.0,
          "SiteName": "Site 1"
        },
        {
          "SiteId": 2.0,
          "SiteName": "Site 2"
        },
        {
          "SiteId": 3.0,
          "SiteName": "Site 3"
        }
      ]
    }
    

    【讨论】:

    • 请看我的问题,我已经添加了反序列化的确切代码。它取自 android 网站上的 GsonRequest。
    • 另外,我尝试添加 `@SerializedName("Sites")` 并且 eclipse 抛出错误。 “提取字符串”并且没有导入选项...
    • @SerializedName 只是遵循java命名约定,这永远无法解决问题。问题在于 JSON 字符串。尝试最后一个选项。
    猜你喜欢
    • 2013-02-02
    • 1970-01-01
    • 2011-04-26
    • 1970-01-01
    • 1970-01-01
    • 2013-03-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多