【问题标题】:Is default no-args constructor mandatory for Gson?Gson 是否必须使用默认的无参数构造函数?
【发布时间】:2013-09-09 19:16:03
【问题描述】:

Gson user guide 声明我们应该为任何类定义默认的无参数构造函数以正确使用 Gson。更重要的是,在 Gson 的 InstanceCreator 类的 javadoc 中,如果我们尝试反序列化缺少默认构造函数的类的实例,则会引发异常,并且我们应该在这种情况下使用 InstanceCreator。但是,我尝试使用缺少默认构造函数的类来测试使用 Gson,并且序列化和反序列化都可以正常工作。

这是反序列化的一段代码。没有非参数构造函数的类:

public class Mushroom {
    private String name;
    private double diameter;

    public Mushroom(String name, double diameter) {
        this.name = name;
        this.diameter = diameter;
    }

    //equals(), hashCode(), etc.
}

还有一个测试:

@Test
public void deserializeMushroom() {
    assertEquals(
            new Mushroom("Fly agaric", 4.0),
            new Gson().fromJson(
                    "{name:\"Fly agaric\", diameter:4.0}", Mushroom.class));
}

效果很好。

所以我的问题是:我真的可以在不需要默认构造函数的情况下使用 Gson,或者在任何情况下它不起作用吗?

【问题讨论】:

    标签: java json gson default-constructor


    【解决方案1】:

    从 Gson 2.3.1 开始。

    不管 Gson 文档怎么说,如果你的类没有无参数构造函数并且你没有注册任何 InstanceCreater 对象,那么它将创建一个 ObjectConstructor (构造你的对象),并带有UnsafeAllocator 使用反射来获取类sun.misc.UnsafeallocateInstance 方法来创建您的类的实例。

    这个Unsafe class 解决了缺少无参数构造函数的问题,并且具有many other dangerous usesallocateInstance 状态

    分配一个实例但不运行任何构造函数。初始化 如果还没有上课。

    所以它实际上不需要构造函数,而是会绕过你的两个参数构造函数。查看一些示例here

    如果您确实有一个无参数构造函数,Gson 将使用 ObjectConstructor,它通过调用使用默认的 Constructor

    yourClassType.getDeclaredConstructor(); // ie. empty, no-args
    

    我的 2 美分:按照 Gson 所说的,使用无参数构造函数创建您的类或注册 InstanceCreator。使用Unsafe 时,您可能会发现自己处于不利地位。

    【讨论】:

    • 如果我有一个默认构造函数将我的最终成员设置为 null,但该成员没有设置器怎么办?这是一个明智的解决方案吗?
    • @thomas.mc.work Gson 将能够通过反射直接设置字段(可能还有一些不安全的工作),您可以通过 getter 检索它(或直接通过字段。我不知道不推荐这种设计。
    • 我找到了一个很好的解决方案来解决库 jackson 的 final 问题,如下所述:stackoverflow.com/a/11838468/2854723
    • 根据https://sites.google.com/site/gson/gson-user-guide#TOC-Using-Gson,您可以使用私有构造函数来防止使用不安全。根据我的测试,当我使用私有构造函数时,GSON 使用以下方法:com.google.gson.internal.newDefaultConstructor 当我删除私有构造函数时,GSON 使用以下方法:com.google.gson.internal。 newUnsafeAllocator
    • @user986730 实际上是相反的:如果没有无参数构造函数,编译器会认为字段始终处于整洁状态,因为它假定将发生正常实例化(运行字段初始化程序,一个声明的构造函数被调用)。然后,现实会给你带来不可能的 NPE,因为不安全的实例化是你不注意时实际发生的事情。
    【解决方案2】:

    Jackson 库中有一个很好的解决方案,如下所述:

    https://stackoverflow.com/a/11838468/2854723

    重点是通过Mix-Ins feature 告诉序列化程序在使用带参数的构造函数时要使用哪些 JSON 字段。

    如果该实体是外部库的一部分,那么您可以使用Creator feature“远程注释”。

    【讨论】:

      【解决方案3】:

      对于raindev 的示例,它可以,因为您的JSON 中包含所有值,因此即使它们没有初始化,它们也会覆盖每个变量。但在许多情况下,可能有一些瞬态字段,或在 JSON 中没有值的可选字段。然后,如果您没有无参数构造函数,则当有人尝试读取该字段时,该字段将保持为 null 和 NPE。

      【讨论】:

        猜你喜欢
        • 2012-11-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多