大多数不熟悉Java的开发人员在没有指定至少一个显式构造函数的情况下 ,会很快了解到为其Java类隐式创建了“ 默认构造函数 ”( 由javac )。 Java语言规范的 8.8.9节简要指出:“如果一个类不包含构造函数声明,则将隐式声明一个默认构造函数。” 该部分进一步描述了隐式创建的默认构造函数的特征,包括它不带参数,不带throws
子句,以及调用类似地不接受任何参数的其超类的构造器。 Java开发人员可以选择显式实现类似于默认构造函数的无参数构造函数(例如,不接受任何参数且不包含throws
子句)。 在本文中,我探讨了一些开发人员可能决定实现显式无参数构造函数而不是依赖于隐式默认构造函数的原因 。
明确指定无参数构造函数的一些原因
排除类的实例化
实施显式无参数构造函数的常见原因是,避免使用public
可访问性隐式创建默认构造函数。 如果类具有其他显式构造函数(接受参数),则这是不必要的步骤,因为任何显式构造函数的存在都会阻止隐式默认构造函数的生成。 但是,如果不存在其他显式构造函数(例如,在具有所有static
方法的“实用程序”类中),则可以通过实现具有private
访问权限的显式无参数构造函数来排除隐式默认构造函数。 Java语言规范的 8.8.10节描述了使用所有private
显式构造函数来防止类的实例化。
通过Builder或静态初始化工厂强制类实例化
显式实现private
无参数构造函数的另一个原因是,通过静态初始化工厂方法或构造器而不是构造函数来强制实例化该类的对象。 Effective Java (第三版)的前两项概述了使用静态初始化工厂方法和生成器比直接使用构造器的优势。
需要多个构造函数,包括无参数构造函数
实现无参数构造函数的一个明显原因可能是与上面讨论的原因一样普遍或更常见,这是当需要无参数构造函数时,但需要参数的构造函数也是如此。 在这种情况下,由于存在其他期望参数的构造函数,因此必须显式创建无参数构造函数,因为永远不会为已经具有一个或多个显式构造函数的类隐式创建默认构造函数。
使用Javadoc构建文档对象
显式实现无参数构造函数而不是依赖隐式创建的默认构造函数的另一个原因是在构造函数上表达Javadoc注释。 这是JDK-8224174 (“ java.lang.Number具有默认构造函数”)的既定理由,该理由现在是JDK 13的一部分,并且也以当前未解决的JDK-8071961表示 (“当默认构造函数为已创建”)。 最近编写的CSR JDK-8224232 (“ java.lang.Number具有默认构造函数”)详细说明了这一点:“默认构造函数不适用于有据可查的API。”
显性优先于隐性优先
与隐式创建相比,某些开发人员通常更喜欢显式规范。 在Java中,可以在显式规范或隐式对应之间进行选择。 如果开发人员重视沟通方面或假定显式构造函数具有更高的可读性,则他们可能更喜欢显式无参数构造函数而不是隐式构造函数。
在JDK中用显式无参数构造函数替换默认构造函数
在JDK中,有些情况下,隐式默认构造函数已被显式无参数构造函数代替。 其中包括:
- JDK 9中已解决的JDK-8071959 (“ java.lang.Object使用隐式默认构造函数”)用显式的无参数构造函数代替了java.lang.Object的“默认构造函数”。 阅读该问题的“描述”使我微笑:“在修改java.lang.Object( JDK-8071434 )上的某些文档时,注意到该类*没有*具有显式构造函数,而是依靠javac创建隐式默认构造函数。 多么尴尬!”
- JDK 9中已解决的JDK-8177153 (“ LambdaMetafactory具有默认构造函数”)用显式(和
private
)无参数构造函数代替了隐式默认构造函数。 - JDK 13计划的JDK-8224174 (“ java.lang.Number具有默认构造函数”)将用显式无参数构造函数替换java.lang.Number的隐式默认构造函数。
关于默认构造函数的潜在javac lint警告
有一天, javac可能会收到可用的lint警告,以指出具有默认构造函数的类。 JDK-8071961 (“当创建默认构造函数时添加javac lint警告”)目前尚不适用于任何特定的JDK版本,它指出:“ JLS第8.8.9节记录了,如果一个类没有声明至少一个构造函数,编译器默认会生成一个构造函数。 尽管此策略可能很方便,但是对于正式类,如果没有其他原因导致默认构造函数没有Javadoc,则这是一种不良的编程习惯。 使用默认构造函数可能是合理的javac lint警告。”
结论
依赖于在编译时创建的默认构造函数绝对很方便,但是在某些情况下,即使不需要显式指定,显式指定无参数构造函数也可能更为可取。
翻译自: https://www.javacodegeeks.com/2019/05/explicit-arguments-constructor-versus-default-constructor.html