【问题标题】:Why do we need a default no argument constructor in Java?为什么我们需要在 Java 中使用默认的无参数构造函数?
【发布时间】:2011-03-05 22:29:52
【问题描述】:

为什么在许多 Java 相关 API 中我们需要一个默认的无参数构造函数?就像一般规则一样,所有 java bean 类或实体类(JPA 等)或 JAX-WS 实现类都需要显式的无参数构造函数。

如果默认情况下 Java 提供无参数构造函数,那么为什么这些标准中的大多数都需要显式构造函数?

【问题讨论】:

    标签: java constructor default-constructor


    【解决方案1】:

    我相信需要public nullary 构造函数的框架这样做是因为它们使用反射来实例化类型,例如通过Class.newInstance()。

    至于为什么 default 构造函数可能不适用于这种情况,这里是相关的 JLS 部分:

    JLS 8.8.9 Default Constructor

    如果class 不包含构造函数声明,则自动提供不带参数的默认构造函数:

    • 如果class被声明为public,则默认构造函数被隐式赋予访问修饰符public;
    • 如果类被声明为protected,则默认构造函数被隐式赋予访问修饰符protected;
    • 如果类被声明为private,则默认构造函数被隐式赋予访问修饰符private;
    • 否则,默认构造函数具有没有访问修饰符隐含的默认访问权限。

    因此,在 public 类中,默认构造函数将具有正确的可见性,否则必须明确提供 public。

    【讨论】:

    • 可见性不是问题,因为它可以通过反射 API 绕过。
    • 而在默认构造函数中调用super()呢,是不是在这里起了作用?
    【解决方案2】:

    如果没有应用其他构造函数,Java 仅提供无参数构造函数。在许多 Java API(例如 JPA、序列化和许多其他从外部表示构建对象)中,在设置对象的数据值之前需要对象的实例,因为如何应用这些值的定义是通过对象的实例成员定义(例如 readExternal(ObjectInput))。如果一个类只有一个带有一些参数的构造函数,那么除非定义了一个单独的无参数构造函数,否则库可能无法构造一个实例。

    值得注意的是,这是特定库的实现者的设计选择,可以构建一个 API/框架,可以外部化和重新创建没有无参数构造函数的对象(定义一个单独的工厂类是一种方法)。需要无参数构造函数的模式首先出现在 Java 序列化(我认为)中,并已被其他库(例如 JPA)采用为事实上的标准方法。这种方法的缺点是它阻止了不可变对象的使用。

    【讨论】:

    • 例如,XStream 可以将对象序列化为 XML,并且不需要无参数构造函数。
    【解决方案3】:

    需要一个构造函数来初始化任何非默认值,并且可以包含所需的副作用。

    如果您的编程风格鼓励数据传输对象的最小构造函数,这似乎是不必要的,但库已选择不为构造函数假定任何编程风格。

    您可以编写一个不假定默认构造函数的库,但您必须对构造函数会做什么和不会做什么做出假设。即我已经编写了这样的库,但也能够强制构造函数可以做什么,这样不直接调用它是安全的。

    【讨论】:

      【解决方案4】:

      Java 仅提供一个默认的无参数构造函数如果没有定义其他构造函数。因此,如果您有其他构造函数,则必须自己显式定义无参数构造函数。

      这些框架使用反射 API 并查看方法名称来确定如何设置属性。构造函数的参数只能按类型而不是名称找到,因此框架无法可靠地将属性与构造函数参数匹配。因此,它们需要一个无参数的构造函数来创建对象,然后可以使用 setter 方法来初始化数据。

      某些框架可能支持@ConstructorProperties 作为替代方案。

      【讨论】:

        【解决方案5】:

        两个原因: 1) 如果引用数据类型的实例数据字段未初始化,则避免 NullPointerException。提供显式构造函数将使您有机会初始化此类数据字段,如果它们在声明时尚未初始化 2) 对于想要使用无参数构造函数的用户;如果存在其他构造函数,这些不会自动提供

        【讨论】:

          【解决方案6】:

          其中许多框架源自“POJO”的早期思想,尤其是JavaBeans。按照惯例,最小的有用 Java 对象将有一个无参数构造函数,并且每个成员都可以通过 get/setProperty1 和 is/setProperty1 等方法访问布尔值。如果类遵循接口的约定,则使用反射的工具和框架可以“开箱即用”。

          【讨论】:

            猜你喜欢
            • 2014-06-13
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2019-01-25
            • 1970-01-01
            • 1970-01-01
            • 2020-11-08
            • 1970-01-01
            相关资源
            最近更新 更多