2012-03-26 152 views
2

我不知道为什么这个代码(在运行时提供了计算器)编译:Java编译混淆:为什么这个代码编译?

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

一般来说,你想要拾取微妙的错误,开发人员不太可能通过读取/运行代码来拾取。在这种情况下,只要您尝试运行它,错误就会很明显。 – 2012-03-26 07:32:07

回答

5

这不是编译时错误,因为编译器无法确定它是否会在编译时无限生成。

我和你可以看看它,但是编译器只关心声明是正确的。没有什么语法上非法这个声明,这就是为什么编译器会放过它。

它与halting problem有关,因为程序无法报告它是否会成功停止。

+1

我不知道编译器,但肯定像Findbugs这样的检查器能够警告这个问题? – Luciano 2012-03-26 05:40:31

0

不,这不是Java的问题。它对于动态声明来说非常快速而且松散,并且不需要在使用它们之前声明事物。它稍后将会显示出来,并且它使语言更易于使用。

0

因为每次你创建的StackOverflow它给你一个堆栈溢出异常,行

StackOverflow overflow = new StackOverflow(); 

创建另一个StackOverflow上,创造一个又一个,等等等等,直到堆栈马克塞斯并抛出一个例外。

+0

我想他知道已经... – UmNyobe 2012-03-26 03:54:17

+2

我想OP知道堆栈为什么溢出,并且问为什么这样的构造是允许的。 – 2012-03-26 03:54:20

1

我认为编译器应该能够捕获这个无限循环的递归版本,但是在语言定义中没有任何东西使得对象在被实例化时构造另一个实例是非法的。

这当然是我希望代码分析工具如FindBugs抱怨。

0

不可以。在编译时,Java不会检测到无限循环或无限递归。 你可以编译像你的代码或下面的方法就好了,它会在运行时炸掉。

private int recurseForever(){ 
    return recurseForever(); 
} 

在你的情况,构造函数创建该类的一个新实例,从而调用另一个构造等。对于为什么它不这样做:因为不可能对所有情况(停止问题)进行处理,并且将资源投入到部分解决方案中(仅在有时会起作用,但会使编译速度始终低于所有人,可能还会引入错误,因为编译器现在更复杂)显然不被认为是一个好主意。

0

由于编译器实际上不可能抓住每一种可能的方式,所以不需要编译器捕获它。一般来说,无限递归只能在运行时检测到。 (即使如此,所有你可以检测到的是,它超过了允许的限制。)

0

我感到困惑的原因是因为在类定义中,我试图创建一个类的对象,我是试图定义。这不应该是一个编译时错误?

当编译器看到这段代码时,你已经完全定义了你的类,并且编译器可以毫不含糊地创建这个类的一个对象。因此这显示没有编译时错误。

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!"); 
    } 
} 
+1

这甚至不会编译。你不能直接从静态方法'main'引用一个实例变量'overflow'。 – 2012-03-26 04:11:59

+0

是的,谢谢你提到我的错误先生 – Krish 2012-03-26 04:19:10