允许递归构造函数有什么好处(如果有的话)?

时间:2010-04-07 18:32:20

标签: java recursion constructor language-theory

在Java中,构造函数不能递归。编译时错误:“递归构造函数调用”。我们假设我们没有这个限制。

要记住的事情:

  • 构造函数的返回类型为void。由于它是一种无效方法,因此无法利用递归的全部功能。
  • 构造函数可以使用this()调用自身(或任何其他构造函数)。但是“对此的调用必须是构造函数中的第一个语句”
  • 我们可以在连续调用之间使用非本地数据来从递归构造函数中获得一些可能的收益。

允许递归构造函数会有什么好处吗?

6 个答案:

答案 0 :(得分:9)

构造函数(当它们相互调用时)就像返回void的方法一样。因此,他们产生结果的唯一方法是副作用。然后,这仅限于改变它们正在构造的对象,或者通过改变作为参数传入的值。后者在构造函数中是一个非常讨厌的想法;构造函数通常从其参数中获取信息而不会改变它们。

因此,改变正在构造的对象是唯一的选择,以便有任何方法来跟踪递归的进度,以便最终终止。而且很难看出它比普通构造函数中的简单循环更容易编写,读取更清晰等等。

在构造函数中调用另一个构造函数(带this)当然与在构造函数中使用new表达式完全不同:

class Node
{
    Node _left, _right;

    public Node(Node left, Node right)
    {
        _left = left != null ? new Node(left._left, left._right) : null;
        _right = right != null ? new Node(right._left, right._right) : null;
    }
}

此处Node构造函数调用自身,但通过新表达式调用。这是至关重要的区别。 new表达式产生一个值,因此这是纯粹的“功能性”,非变异的东西,并提供了一种方便的方法来制作节点树的深层副本。

答案 1 :(得分:1)

Constructors can be recursive。 (那是在C#中,但你可以用Java做同样的事情)

答案 2 :(得分:1)

让我们来看看这个问题。首先,当您调用new MyClass("foo");时会发生什么?那么有两件事情发生了。首先,虚拟机将分配存储类型为MyClass的对象所需的内存。然后,调用构造函数。构造函数的工作是初始化这个刚刚分配的内存。因此,构造函数根本没有返回类型(甚至没有void)。 new运算符返回的值是对已分配内存的引用,因此构造函数也不能返回。

然后,递归构造函数调用的好处是什么。这种调用的唯一好处是像其他一样处理某些构造函数参数,并通过重新调用构造函数来执行此操作。虽然这是可能的,但通常很容易调整构造函数本身的值(使用非final参数),然后初始化对象属性(简而言之,你不需要递归)。

其次,通过将所有工作卸载到可以根据需要递归的工作方法,您可以相当容易地进行递归。

一个更有趣的问题是对超级或此调用的限制是构造函数的第一个语句。这种限制可能是为了阻止草率或不安全的编程实践。声明在这里以粗体显示,因为可以(尽管不是很漂亮)解决这个限制。如果你还记得表达式可能有副作用(例如变量赋值),并且在调用本身之前调用用于参数的表达式,则可以创建复杂的表达式,在调用委托构造函数之前执行所有计算。

您希望稍后在构造函数体中调用委托/超级构造函数的一般原因是参数操作。您可以使用(静态)辅助函数执行这些计算并提供正确的值。这通常更干净但并非在所有情况下都是如此。实际执行速度不应受到影响,因为热点可以很好地内联这些内容。

这意味着最终的考虑归结为提供委托/超级电话的自由放置的灵活性,而不是通过使不正确的做法更加困难而提供的额外安全性。 Java设计师(以及一般的Java哲学)所做出的选择是,以专家手中的原始语言能力(复杂性增加)为代价,更难以做错事。做出的选择对我来说是一个有效的选择,虽然我个人希望有这样的权力(人们总是可以在没有这些限制的JVM上实现java ++语言)。

答案 3 :(得分:0)

您可能无法编写递归构造函数,但可以从构造函数中调用递归函数。我以前从来没有这么做过,我想不出你可能需要的情况,但如果你愿意,你可以做到。

答案 4 :(得分:0)

你的意思是什么?您可以在Java中使用递归构造函数。它们允许您以更分层的方式重用代码并设计构造函数。

在下面的递归构造函数示例中,我可以调用new User()new User("Marcus"),并使用我使用的构造函数,newUser设置为true

public class User() {
  public String userName;
  public boolean newUser;
  User() {
    newUser = true;
  }
  User(String userName) {
    // Recursively call no-argument constructor
    this();
    this.userName = userName;
  }
}

没有递归构造函数,这是同样的事情。请注意重复的代码行:

public class User() {
  public String userName;
  public boolean newUser;
  User() {
    newUser = true;
  }
  User(String userName) {
    newUser = true;
    this.userName = userName;
  }
}

在下面的非递归构造函数示例中,如果我没有将名称传递给构造函数,则名称将设置为“New User”。如果我没有设置名称,我只想调用无参数构造函数。如果我在这里做了递归构造函数调用,我最终会设置userName两次:

public class User() {
  public String userName;
  User() {
    this.userName = "New User";
  }
  User(String userName) {
    this.userName = userName;
  }
}

如果您:

,您将只使用递归构造函数
  1. 拥有多个构造函数
  2. 在构造函数中包含代码
  3. 想要递归使用另一个构造函数中的代码

答案 5 :(得分:0)

  

构造函数的返回类型是   空隙。

不,不是。

  

构造函数可以使用this()

调用自身(或任何其他构造函数)

没有。它只能调用其他构造函数,并且只有在不会导致当前构造函数的递归调用时才会调用它。这就是你收到你提到的错误信息的原因。

  

我们之间可以使用非本地数据   连续打电话仍然有一些   从递归中获得可能的收益   构造

如何?你为什么要重新 -initialize一个对象?什么时候不能一次顺序完成?从未在39年的计算机编程和20年的OO中遇到过这个问题。

  

会有什么好处吗?   允许递归构造函数?

你还没有想出任何......