2010-12-17 108 views
3

這個Java代碼爲什麼產生StackOverflowError?我明白,這與某種方式與遞歸泛型類型參數相關聯。但我不明白整個機制。爲什麼我在這裏得到StackOverflowError?

public class SomeClass<T extends SomeClass> { 

    SomeClass() { 
     new SomeClassKiller(); 
    } 

    private class SomeClassKiller extends SomeClass<T> { 
    } 

    public static void main(String[] args) { 
     new SomeClass(); 
    } 
} 
+0

您是否看過錯誤的堆棧跟蹤?這應該讓你知道發生了什麼。它與類型參數沒有任何關係 - 如果刪除它們,它仍會給出一個'StackOverflowError'。 – Jesper 2010-12-17 11:03:32

+3

在stackoverflow上的好問題。 (: – 2010-12-17 11:03:44

+0

@Jesper:SomeClassKiller正在初始化無限次數,但我不明白爲什麼。 – Roman 2010-12-17 11:04:41

回答

13

通用部分無關緊要的評論 - 也不是真正的問題該類是嵌套的。看着這主要是相當於對類,它應該是比較明顯的:

public class SuperClass 
{ 
    public SuperClass() 
    { 
     new SubClass(); 
    } 
} 

public class SubClass extends SuperClass 
{ 
    public SubClass() 
    { 
     super(); 
    } 
} 

所以子類構造函數調用父類的構造 - 然後創建一個新的子類,它調用到超類構造函數,它創建了一個新的子類等...砰!

+0

呵呵..我絕對確信泛型的問題並沒有注意到這個東西:) – Roman 2010-12-17 11:07:23

+0

'super() ;'*幾乎等於'this = new SuperClass();'。現在應該很明顯... – 2010-12-17 11:07:53

2

這是從另一個和它的前一個循環鏈構造函數調用了一個構造函數,見下

public class SomeClass<T extends SomeClass> { 

    SomeClass() {//A 
     new SomeClassKiller();// calls B 
    } 

    private class SomeClassKiller extends SomeClass<T> {//B 
       //calls A 
    } 

    public static void main(String[] args) { 
     new SomeClass(); //calls A 
    } 
} 
1

這是因爲遞歸構造函數調用發生在類SomeClass和 SomeClassKiller之間。

0
public class SomeClass<T extends SomeClass> { 

    SomeClass() { 
     new SomeClassKiller(); 
    } 

    private class SomeClassKiller extends SomeClass<T> { 
     public SomeClassKiller() 
     { 
     super(); //calls the constructor of SomeClass 
     } 
    } 

    public static void main(String[] args) { 
     new SomeClass(); 
    } 
} 

由編譯器產生的代碼是這樣的,所以當u創建一個對象,它recursivly調用SomeClass的和SomeClassKiller永遠。

0

構造函數是從上到下調用​​的,也就是說,如果A類從B派生,A的構造函數將首先調用父構造函數(B)。

在你的情況下,new SomeClassKiller()遞歸地調用SomeClass的構造函數,這又構造了另一個SomeClassKiller ......它就是這樣。

0

main()方法是創建的SomeClass一個新實例,它調用SomeClass構造創建,默認情況下調用父類的構造併發生計算器的SomeClassKiller一個新的實例。

爲了避免堆棧溢出。將代碼更改爲如下所示:

public class SomeClass<T extends SomeClass> { 

    SomeClass() { 
     new SomeClassKiller(); 
    } 

    private class SomeClassKiller extends SomeClass<T> { 
     public SomeClassKiller(){ 
      //super(); does this by default, but is now commented out and won't be called. 
     } 

    } 

    public static void main(String[] args) { 
     new SomeClass(); 
    } 
} 
相關問題