我有以下代码示例:
public class example {
// class constructor
public example(){}
public void foo() {
example o = new example();
...
}
}
为什么可以编译并运行它而不导致StackOverflowError
?
答案 0 :(得分:3)
您声称这将导致StackOverflowError
。但是,StackOverflowError
仅在方法无限期地直接或间接调用自身时才会发生。
在您的情况下,foo
必须自我调用以使堆栈溢出。让我们看看foo
的作用。
example o = new example();
调用foo
时,它将调用example
的构造函数,您在此处已声明:
public example(){}
构造函数在返回之前不执行任何操作。现在,构造函数已经返回,o
被分配了新创建的实例,foo
返回了,因为它无事可做。请注意,foo
尚未再次调用。
您的误解可能是您错误地认为,在调用构造函数时,也会调用该类的所有方法。除非您实际上在构造函数中调用了方法,否则情况并非如此:
public example(){ foo(); } // this will cause stack overflow
答案 1 :(得分:2)
这样做的唯一原因是:foo
并未作为example
初始化的一部分被调用。
JLS defines a lifecycle关于类更新的内容。
在这种情况下,以下两行是相关的:
在每种情况下,都将特定的构造函数(第8.8节)标识为 被指定参数(可能没有参数)作为 类实例的创建过程。
无论何时创建新的类实例,都会分配内存空间 为此,在类中声明的所有实例变量都有空间 类型和在实例的每个超类中声明的所有实例变量 类类型,包括所有可能隐藏的实例变量 (§8.3)。
因此,这意味着除非在对象分配期间内存不足,否则不会遇到任何问题。
您显式调出StackOverflowError
,这仅发生在进行的递归调用中。仅当您这样做是愚蠢的时,这种情况才会发生:
class Example {
Example e;
public Example() {
e = new Example();
}
}
每次调用new
都将迫使该对象new
直到另一个对象用尽,这仅仅是因为new
处理对象取决于其自身是new
如果在构造函数中调用foo
,也可以完成同样的事情。
class Example {
Example e;
public Example() {
foo();
}
public void foo() {
Example o = new Example();
}
public static void main(String[] args) {
new Example();
}
}
只要实例化对象时未调用foo
,在 this 情况下,诸如您所声明的内容的声明不会导致{{1} }。