什么时候可以在该类的方法中创建类的对象?

时间:2012-10-24 07:56:52

标签: java class

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

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

7 个答案:

答案 0 :(得分:21)

  

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

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

想想你的主要方法是在课外。这将创建您的类的实例,并使用创建的实例。因此,当您从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 
    }
}

答案 1 :(得分:5)

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

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

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

答案 2 :(得分:2)

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

答案 3 :(得分:1)

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

答案 4 :(得分:1)

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

答案 5 :(得分:1)

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();
  }
}

这是唯一有问题的例子。编译器没有抱怨。 可以转换为字节代码,可以执行。但是,在运行时,会导致堆栈溢出:

  • 分配了新的失败
  • 其no-arg构造函数被称为
  • 构造函数尝试创建新的失败
  • 分配了新的失败
  • 其no-arg构造函数被称为
  • ...

编译器允许这样做,因为通常编译器不能阻止所有无限递归。编译器允许任何可以转换为字节码的内容

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

答案 6 :(得分: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 方法的类)中实例化(创建对象)其他类。这样你就可以运行一次代码。