【问题标题】:Is there a reason to explicitly code a default constructor when there are no other constructors?当没有其他构造函数时,是否有理由显式编写默认构造函数?
【发布时间】:2010-02-18 20:12:24
【问题描述】:

我最近在一个类中看到了这个构造函数:

public MyClass(){ }

没有其他构造函数。

这是有原因的吗? Java 会自动创建一个默认构造函数,那么为什么要显式声明一个呢?或者这被认为是一种好的做法,就像在单语句 if 语句中使用大括号一样 - 以防以后添加其他构造函数并且您忘记了您没有默认值...?

【问题讨论】:

  • 关于语义的注释,这种构造函数的正确名称是“无参数构造函数”。当编译器默认为您生成它时,它只是一个“默认”构造函数。

标签: java default-constructor


【解决方案1】:

有几点不太可能是您在这种情况下看到它的原因。

  • 它可以让您设置断点。
  • 您可以将其设为非公开

至于“以防以后添加其他构造函数而您忘记了自己没有默认值”-我想这可能是一个原因。但是如果添加了非默认构造函数,任何使用默认构造函数的代码都将无法编译,因此添加新构造函数的人通常还需要添加默认 ctor 的定义。

再一次,我想不出定义空 ctor 有什么特别的危害(尽管现在我已经输入了它,但我感觉有人可能会指出 C++ 的某个角落,它可能会咬你) .

【讨论】:

  • 它可能是由 IDE 自动创建的,或者是删除非默认构造函数后遗留下来的。此外,众所周知,我会在我知道需要默认值的类上创建此类构造函数(即,由于某些序列化或数据绑定要求),并且不想在稍后创建第二个构造函数时被问题所困扰。
  • 只为“以防我以后需要为其他内容添加代码”而编写的代码是代码异味
  • @Michael - :) 设置断点...虽然你真的可以在类上设置断点(公共类 MyClass...)。 @matt b - 总是这样吗?我经常听到人们提倡在单语句 if 周围使用大括号,因为您可以稍后添加其他语句,假设它们将作为 if 的一部分执行,从而产生一个微妙的错误。不过,这个例子可能有点牵强,应该很容易理解。
  • @froadie:关于大括号的观点很好,但我觉得这是不同的,因为它增加了可读性(另一个重要目标)。另外,与整个构造函数相比,多了两个大括号它的冗余性要少得多...
【解决方案2】:

它没有任何作用,可以安全地删除。

【讨论】:

    【解决方案3】:

    Java 语言规范是这样说的:

    如果一个类不包含构造函数 声明,然后是默认值 不带参数的构造函数 自动提供:

    • 如果被声明的类是原始类 Object,那么 默认构造函数的主体为空。
    • 否则,默认构造函数不带参数,只是调用 没有的超类构造函数 论据。

    所以无论如何都会创建默认构造函数。不写就没有意义。不得不。

    IMO 仅当您想更改构造函数的可见性级别时才应该这样做,即使其私有或受包保护

    【讨论】:

      【解决方案4】:

      虽然在技术层面显式添加构造函数并没有获得任何好处,但仍有潜在的理由这样做。一种是如果类是通过反射实例化的,您可能希望在默认构造函数上放置一些文档以表明它是必需的,即使添加新构造函数不会导致编译错误。

      另一个是一些编码标准更喜欢它,以便明确地表明你考虑过这个类应该有什么样的构造函数。

      【讨论】:

      • +1 表示“类通过反射实例化”:某些框架可能会这样做,并且没有无参数构造函数会破坏它们(在运行时:-( )。但这应该 绝对在构造函数javadocs中记录。
      • 如果类是通过反射实例化的,我更喜欢测试用例来确保没有人意外破坏这个方面。
      【解决方案5】:

      因为你相信the zen of python的第二句话:

      显式优于隐式。

      【讨论】:

      • 这是真的吗?我可以想到这样一个声明的很多烦人的后果......(总是显式扩展 Object,例如。)
      • 我会说是。在最坏的情况下,您会变得冗长,但它不会造成任何伤害,并且在寻找错误或试图弄清楚全局时会将所有内容都放在您面前。在您的具体情况下,我从不喜欢这种语法糖:如果我的类可以生成实例,它需要一个构造函数,那么为什么要隐藏它呢?我的不喜欢可能来自 Java 的一般冗长和突然的特别奖励之间的对比:包含构造函数。有一个构造函数并不丢人,对吧?
      【解决方案6】:

      如果我错了,请纠正我(我已经有一段时间没有做 Java了),但这不会阻止调用父构造函数吗?在这种情况下,推理显然是父母会自动做一些你不想在这个班级发生的事情。

      【讨论】:

      • 不,super() 调用仍然是隐式的。你无法避免在 Java 中调用父构造函数。
      • @mmyers - 即使在参数构造函数中?还是只是默认?
      • 如果构造函数没有显式调用超类构造函数,Java 编译器会自动插入对超类的无参数构造函数的调用。如果超类没有无参数构造函数,则会出现编译时错误。 Object 确实有这样的构造函数,所以如果 Object 是唯一的超类,没有问题。
      【解决方案7】:

      我被告知 java bean 规范需要公共默认构造函数。维基百科页面 http://en.wikipedia.org/wiki/Java_Bean 也将其列为要求。

      另一方面,我查看了 Sun/Oracle 网站,但找不到提及它的内容。见http://java.sun.com/developer/onlineTraining/Beans/Beans1/simple-definition.html

      【讨论】:

      • 是的,但它隐式存在,这对于 java bean 规范应该没问题。我不认为 java bean 需要你显式创建一个,它只需要它存在
      【解决方案8】:

      实际上有充分的理由将这些答案中未提及的内容包含在内:

      如果无参数构造函数的存在是对象契约的明确一部分,则应明确说明

      如果您明确打算让客户端对您的代码进行子类化,例如Java Swing,那么即使没有其他构造函数,显式创建一个可访问的无参数构造函数也是一个好主意。否则,如果另一个程序员根据他们的智慧决定创建另一个构造函数,新的显式构造函数将删除隐式无参数构造函数并破坏客户端代码。

      如果代码在您自己的代码库中被子类化,那么这将显示为编译器错误,但如果您的代码要作为 jar 发布,并由客户端进行子类化,则不会出现编译器错误。

      当然,您可以争辩说,如果它是您合同的一部分,那么您应该为此进行 junit 测试,您是对的!但是,如果您正在处理一个大型代码库,而您的日常构建需要几个小时来运行测试,那么会破坏您的日常构建,因为您忘记了在添加构造函数时必须显式创建无参数构造函数,而显式构造函数会浪费大量时间并且评论可以避免任何出错的机会。

      优秀代码的目标是让其他开发人员尽可能轻松地更改它而不会出错!

      【讨论】:

      • “否则,如果另一个程序员根据他们的智慧决定创建另一个构造函数,” ...如果他有一个没有任何构造函数的类,那么他应该能够了解对代码的影响,如果他创建了第一个(explizit)构造函数。 (只是我的两分钱)
      猜你喜欢
      • 2023-03-20
      • 2016-10-16
      • 2016-07-18
      • 2017-07-15
      • 2021-09-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多