31
public class TestClass(){
    public static void main(String []args) {
        TestClass t1 = new TestClass();
        t1.anything();
    }
}

在同一个类的定义中创建对象不奇怪吗?因为然后作为响应 - 这个对象创建一个新对象,然后这个新对象创建另一个,无限循环开始永远不会结束,直到内存已满。

4

7 回答 7

27

在同一个类的定义中创建一个对象,而不是响应对象创建一个新对象然后这个新对象创建另一个对象并开始无限循环,这并不奇怪吗?

不,main 方法仅在您运行程序时运行一次。它不会再次执行。因此,该对象只会被创建一次。

想想你的主要方法是在你的课堂之外。它创建您的类的实例,并使用创建的实例。因此,当您从方法创建实例时main,会调用构造函数来初始化实例的状态,然后当构造函数返回时,会执行 main 方法的下一条语句。

实际上,您可以认为main方法不是类实例状态的一部分。

但是,如果您在构造函数中创建了类的实例(例如 0-arg),并将引用作为实例引用变量,那么这将变成无限递归。

public class A {
    private A obj;
    public A() {
        obj = new A();  // This will become recursive creation of object.
                        // Thus resulting in StackOverflow 
    }
}
于 2012-10-24T07:58:46.623 回答
6

如果您尝试执行以下操作,则只会出现无限循环(堆栈溢出错误):

public class TestClass {
    public TestClass() {
        TestClass t = new TestClass();
    }
}

在其他地方,您尝试创建 class 的对象TestClass

于 2012-10-24T08:01:49.057 回答
3
public class TestClass{
  public static void main(String []args) {
    TestClass t1 = new TestClass();
    t1.anything();
  }
}

这是一个完全有效的代码。调用该main方法时,不存在之前的实例TestClass(不需要,因为该main方法是static)。

public class Test2{
  public Test2 clone(){
    return new Test2();
  }
}

这也是完全有效的。当您创建 Test2 的新实例时,它包含该clone方法,但该方法不会自动执行。只有在clone调用该方法时,才会再创建一个 Test2 实例。

public class MyLinkedList{
  MyLinkedList next;
  MyLinkedList(int elems){
    if(elems>0){
      next = new MyLinkedList(elems-1);
    }else{
      next = null;
    }
  }
}

即使构造函数使用相同的构造函数创建新实例也是完全有效的,因为创建受条件保护,因此创建实例有时会触发新创建。

public class Fail{
  public Fail(){
    new Fail();
  }
}

是这里唯一有问题的例子。编译器不会抱怨。它可以被翻译成字节码并且可以被执行。但是,在运行时,您会导致堆栈溢出:

  • 分配了一个新的失败
  • 它的无参数构造函数被调用
  • 构造函数尝试创建一个新的 Fail
  • 分配了一个新的失败
  • 它的无参数构造函数被调用
  • ...

编译器允许这样做,因为通常编译器无法阻止所有无限递归。编译器允许任何可以翻译成字节码的东西。

但是,如果编译器检测到方法或方法链无条件地调用自身,则编译器可能会发出警告

于 2012-10-24T08:16:12.273 回答
2

这并不奇怪。我知道的所有面向对象的语言都允许这样做。代码在语义上是对象定义的一部分,但实际上它可以被认为与任何给定对象的实际状态分开。所以没有循环,因为对象构造不会调用你的方法(当然,除非它调用了——那么你就有问题了)。

于 2012-10-24T07:59:44.340 回答
1

当您使用 new 创建对象构造函数时,会调用初始化实例变量的构造函数,直到您的超类的所有构造函数都被调用为止。如果您将一些代码放在每次创建对象时都会运行的构造函数中

于 2012-10-24T07:59:55.377 回答
1

当程序启动时,它会执行 main 方法。在java中,您不能在类之外创建方法。所有方法都必须封装在一个类中。因此,作为程序入口点的 main 方法必须在一个类中。当你运行这个程序时, main 方法将运行一次并执行其中的代码。在您的情况下,它会创建一个封闭类的对象TestClass。这不必发生。它也可以在这个类之外创建对象。正如@adarshr 的回答中所解释的,您只会得到一个无限循环。

于 2012-10-24T08:03:15.967 回答
1

这一点都不奇怪。你看,main()方法是执行的起点。形象地说,java 是“盲目的”(看不到您告诉它执行/运行的内容),除非它“看到”了该main()方法。在“看到”该main()方法之后,它现在有能力执行随后的其他指令,因此作为外卖,该main()方法首先不属于它自己的类中的对象。

而对于递归,它只会在您执行@Rohit Jain 所说的那样时发生。或者根据您的代码,您不调用anything,而是调用它main()本身。

    public static void main(String []args) {
        TestClass t1 = new TestClass();
        main(String[] args);
    }
}

引用变量t1实际上没有调用main,因为它是静态的。好消息是,main不是由您的代码调用,而是由“jvm”调用,所以严格来说,您不能从那里删除静态。它会导致一些好的错误消息明确告诉您静态应该在那里。这就是为什么您main()在上面的代码片段中看到没有被对象调用的原因。

如果您执行这些操作,则除此之外还会发生递归,您可以安全地在它自己的类中创建一个对象。尽管如此,我不建议这样做。让一个类拥有该main()方法并在该 Main 类(包含 main 方法的类)中实例化(创建对象)其他类。这样你就可以运行一次代码。

于 2021-04-02T21:14:38.357 回答