我不确定为什么这段代码(在运行时给出stackoverflow)编译:
import java.io.*;
import java.util.*;
public class StackOverflow {
StackOverflow overflow = new StackOverflow();
public void myCall() {
overflow.myPrint();
}
public static void main(String[] args) {
StackOverflow newStackOverflow = new StackOverflow();
newStackOverflow.myCall();
}
public void myPrint() {
System.out.println("I am confused!");
}
}
我感到困惑的原因是因为在类定义中,我正在尝试创建我想要定义的类的对象。这不应该是编译时错误吗?
答案 0 :(得分:5)
这不是编译时错误,因为编译器无法判断它是否会在编译时无限生成。
你和我可以看一下并确实看到它,但编译器只关心声明是否正确。这个声明没有语法非法,这就是为什么编译器会放弃它。
它与halting problem有关,因为程序无法报告它是否会成功停止。
答案 1 :(得分:1)
我认为可以说,编译器应该捕获无限循环的递归版本,但是语言定义中没有任何内容使得对象在实例化时构造自身的另一个实例是非法的。
我当然希望像FindBugs这样的代码分析工具能够抱怨。
答案 2 :(得分:0)
这不是Java的问题。它在动态声明方面非常快速而且松散,并且在使用之前不需要声明事物。它会在以后发现它,它使语言更容易使用。
答案 3 :(得分:0)
它会为您提供堆栈溢出异常,因为每次创建StackOverflow时,该行
StackOverflow overflow = new StackOverflow();
创建另一个StackOverflow,创建另一个,依此类推,直到堆栈最大化并抛出异常。
答案 4 :(得分:0)
没有。 Java无法在编译时检测无限循环或无限递归。 你可以编译像你的代码或下面的方法,它会在运行时爆炸。
private int recurseForever(){
return recurseForever();
}
在您的情况下,构造函数创建类的新实例,从而调用另一个构造函数,依此类推。
至于为什么它没有这样做:因为不可能在所有情况下(停止问题),并将资源投入到部分解决方案(仅在某些情况下有效,但是使编译速度变慢,对所有人来说,可能还引入了错误,因为编译器现在更复杂了)显然不是一个好主意。
答案 5 :(得分:0)
由于编译器实际上不可能捕获每种可能的方法,因此不需要编译器捕获它。通常,无限递归只能在运行时检测到。 (即便如此,您可以检测到的是它超出了允许的限制。)
答案 6 :(得分:0)
我感到困惑的原因是因为在类定义中,我正在尝试创建我想要定义的类的对象。这不应该是编译时错误吗?
当编译器看到这段代码时,您已经完全定义了您的类,编译器可以创建该类的对象而不会产生歧义。因此,这显示没有编译时错误。
答案 7 :(得分:0)
不,它不应该给出错误,通过编写以下行StackOverflow overflow = new StackOverflow();
,您实际上是在类中创建实例变量。这一行StackOverflow newStackOverflow = new StackOverflow();
将创建您的本地变量。
如果您按如下方式更新代码,那么它也会起作用。
import java.io.*;
import java.util.*;
public class StackOverflow {
private static StackOverflow overflow = new StackOverflow();
public void myCall() {
overflow.myPrint();
}
public static void main(String[] args) {
overflow.myCall();
}
public void myPrint() {
System.out.println("I am confused!");
}
}