2012-03-26 197 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