




版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)
文檔簡介
第Java中的StackOverflowError錯誤問題及解決方法目錄StackOverflowError簡介StackFrames和StackOverflowerError的發(fā)生方式StackOverflowerError正在運(yùn)行解決StackOverflowError結(jié)論
StackOverflowError簡介
StackOverflowError可能會讓Java開發(fā)人員感到惱火,因為它是我們可能遇到的最常見的運(yùn)行時錯誤之一。在本文中,我們將通過查看各種代碼示例以及如何處理它來了解此錯誤是如何發(fā)生的。StackFrames和StackOverflowerError的發(fā)生方式讓我們從基礎(chǔ)開始。調(diào)用方法時,將在調(diào)用堆棧上創(chuàng)建新的堆棧幀(stackframe)。該堆棧框架包含被調(diào)用方法的參數(shù)、其局部變。
StackOverflowError可能會讓Java開發(fā)人員感到惱火,因為它是我們可能遇到的最常見的運(yùn)行時錯誤之一。
在本文中,我們將通過查看各種代碼示例以及如何處理它來了解此錯誤是如何發(fā)生的。
StackFrames和StackOverflowerError的發(fā)生方式
讓我們從基礎(chǔ)開始。調(diào)用方法時,將在調(diào)用堆棧上創(chuàng)建新的堆棧幀(stackframe)。該堆棧框架包含被調(diào)用方法的參數(shù)、其局部變量和方法的返回地址,即在被調(diào)用方法返回后應(yīng)繼續(xù)執(zhí)行方法的點。
堆棧幀的創(chuàng)建將繼續(xù),直到到達(dá)嵌套方法中的方法調(diào)用結(jié)束。
在此過程中,如果JVM遇到?jīng)]有空間創(chuàng)建新堆棧幀的情況,它將拋出StackOverflower錯誤。
JVM遇到這種情況的最常見原因是未終止/無限遞歸StackOverflowerr的Javadoc描述提到,錯誤是由于特定代碼段中的遞歸太深而引發(fā)的。
然而,遞歸并不是導(dǎo)致此錯誤的唯一原因。在應(yīng)用程序不斷從方法內(nèi)調(diào)用方法直到堆棧耗盡的情況下,也可能發(fā)生這種情況。這是一種罕見的情況,因為沒有開發(fā)人員會故意遵循糟糕的編碼實踐。另一個罕見的原因是方法中有大量局部變量。
當(dāng)應(yīng)用程序設(shè)計為類之間具有循環(huán)關(guān)系時,也可以拋出StackOverflowError。在這種情況下,會重復(fù)調(diào)用彼此的構(gòu)造函數(shù),從而引發(fā)此錯誤。這也可以被視為遞歸的一種形式。
另一個引起此錯誤的有趣場景是,如果一個類在同一個類中作為該類的實例變量實例化。這將導(dǎo)致一次又一次(遞歸)調(diào)用同一類的構(gòu)造函數(shù),最終導(dǎo)致堆棧溢出錯誤。
StackOverflowerError正在運(yùn)行
在下面所示的示例中,由于意外遞歸,開發(fā)人員忘記為遞歸行為指定終止條件,將拋出StackOverflowError錯誤:
publicclassUnintendedInfiniteRecursion{
publicintcalculateFactorial(intnumber){
returnnumber*calculateFactorial(number-1);
}
在這里,對于傳遞到方法中的任何值,在任何情況下都會引發(fā)錯誤:
publicclassUnintendedInfiniteRecursionManualTest{
@Test(expected=ahref="/tag/stackoverflowerror"rel="externalnofollow"rel="externalnofollow"title="查看更多關(guān)于StackOverflowError的文章"target="_blank"StackOverflowError/a.class)
publicvoidgivenPositiveIntNoOne_whenCalFact_thenThrowsException(){
intnumToCalcFactorial=1;
UnintendedInfiniteRecursionuir
=newUnintendedInfiniteRecursion();
uir.calculateFactorial(numToCalcFactorial);
@Test(expected=StackOverflowError.class)
publicvoidgivenPositiveIntGtOne_whenCalcFact_thenThrowsException(){
intnumToCalcFactorial=2;
UnintendedInfiniteRecursionuir
=newUnintendedInfiniteRecursion();
uir.calculateFactorial(numToCalcFactorial);
@Test(expected=StackOverflowError.class)
publicvoidgivenNegativeInt_whenCalcFact_thenThrowsException(){
intnumToCalcFactorial=-1;
UnintendedInfiniteRecursionuir
=newUnintendedInfiniteRecursion();
uir.calculateFactorial(numToCalcFactorial);
}
但是,在下一個示例中,指定了終止條件,但如果將值-1傳遞給calculateFactorial()方法,則永遠(yuǎn)不會滿足終止條件,這會導(dǎo)致未終止/無限遞歸:
publicclassInfiniteRecursionWithTerminationCondition{
publicintcalculateFactorial(intnumber){
returnnumber==11:number*calculateFactorial(number-1);
}
這組測試演示了此場景:
publicclassInfiniteRecursionWithTerminationConditionManualTest{
@Test
publicvoidgivenPositiveIntNoOne_whenCalcFact_thenCorrectlyCalc(){
intnumToCalcFactorial=1;
InfiniteRecursionWithTerminationConditionirtc
=newInfiniteRecursionWithTerminationCondition();
assertEquals(1,irtc.calculateFactorial(numToCalcFactorial));
@Test
publicvoidgivenPositiveIntGtOne_whenCalcFact_thenCorrectlyCalc(){
intnumToCalcFactorial=5;
InfiniteRecursionWithTerminationConditionirtc
=newInfiniteRecursionWithTerminationCondition();
assertEquals(120,irtc.calculateFactorial(numToCalcFactorial));
@Test(expected=StackOverflowError.class)
publicvoidgivenNegativeInt_whenCalcFact_thenThrowsException(){
intnumToCalcFactorial=-1;
InfiniteRecursionWithTerminationConditionirtc
=newInfiniteRecursionWithTerminationCondition();
irtc.calculateFactorial(numToCalcFactorial);
}
在這種特殊情況下,如果將終止條件簡單地表示為:
publicclassRecursionWithCorrectTerminationCondition{
publicintcalculateFactorial(intnumber){
returnnumber=11:number*calculateFactorial(number-1);
}
下面的測試在實踐中顯示了這種情況:
publicclassRecursionWithCorrectTerminationConditionManualTest{
@Test
publicvoidgivenNegativeInt_whenCalcFact_thenCorrectlyCalc(){
intnumToCalcFactorial=-1;
RecursionWithCorrectTerminationConditionrctc
=newRecursionWithCorrectTerminationCondition();
assertEquals(1,rctc.calculateFactorial(numToCalcFactorial));
}
現(xiàn)在讓我們來看一個場景,其中StackOverflowError錯誤是由于類之間的循環(huán)關(guān)系而發(fā)生的。讓我們考慮ClassOne和ClassTwo,它們在其構(gòu)造函數(shù)中相互實例化,從而產(chǎn)生循環(huán)關(guān)系:
publicclassClassOne{
privateintoneValue;
privateClassTwoclsTwoInstance=null;
publicClassOne(){
oneValue=0;
clsTwoInstance=newClassTwo();
publicClassOne(intoneValue,ClassTwoclsTwoInstance){
this.oneValue=oneValue;
this.clsTwoInstance=clsTwoInstance;
}
publicclassClassTwo{
privateinttwoValue;
privateClassOneclsOneInstance=null;
publicClassTwo(){
twoValue=10;
clsOneInstance=newClassOne();
publicClassTwo(inttwoValue,ClassOneclsOneInstance){
this.twoValue=twoValue;
this.clsOneInstance=clsOneInstance;
}
現(xiàn)在讓我們假設(shè)我們嘗試實例化ClassOne,如本測試中所示:
publicclassCyclicDependancyManualTest{
@Test(expected=StackOverflowError.class)
publicvoidwhenInstanciatingClassOne_thenThrowsException(){
ClassOneobj=newClassOne();
}
這最終導(dǎo)致了StackOverflowError錯誤,因為ClassOne的構(gòu)造函數(shù)實例化了ClassTwo,而ClassTwo的構(gòu)造函數(shù)再次實例化了ClassOne。這種情況反復(fù)發(fā)生,直到它溢出堆棧。
接下來,我們將看看當(dāng)一個類作為該類的實例變量在同一個類中實例化時會發(fā)生什么。
如下一個示例所示,AccountHolder將自身實例化為實例變量JointaCountHolder:
publicclassAccountHolder{
privateStringfirstName;
privateStringlastName;
AccountHolderjointAccountHolder=newAccountHolder();
}
當(dāng)AccountHolder類實例化時,由于構(gòu)造函數(shù)的遞歸調(diào)用,會引發(fā)StackOverflowError錯誤,如本測試中所示:
publicclassAccountHolderManualTest{
@Test(expected=StackOverflowError.class)
publicvoidwhenInstanciatingAccountHolder_thenThrowsException(){
AccountHolderholder=newAccountHolder();
}
解決StackOverflowError
當(dāng)遇到StackOverflowError堆棧溢出錯誤時,最好的做法是仔細(xì)檢查堆棧跟蹤,以識別行號的重復(fù)模式。這將使我們能夠定位具有問題遞歸的代碼。
讓我們研究一下由我們前面看到的代碼示例引起的幾個堆棧跟蹤。
如果忽略預(yù)期的異常聲明,則此堆棧跟蹤由InfiniteCursionWithTerminationConditionManualTest生成:
java.lang.StackOverflowError
atc.b.s.InfiniteRecursionWithTerminationCondition
.calculateFactorial(InfiniteRecursionWithTerminationCondition.java:5)
atc.b.s.InfiniteRecursionWithTerminationCondition
.calculateFactorial(InfiniteRecursionWithTerminationCondition.java:5)
atc.b.s.InfiniteRecursionWithTerminationCondition
.calculateFactorial(InfiniteRecursionWithTerminationCondition.java:5)
atc.b.s.InfiniteRecursionWithTerminationCondition
.calculateFactorial(InfiniteRecursionWithTerminationCondition.java:5)
在這里,可以看到第5行重復(fù)
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- QC-T 375-1999 一端固定式單管夾片
- 2025年中考數(shù)學(xué)沖刺復(fù)習(xí)《幾何圖形》含答案解析
- 2026年高考?xì)v史一輪復(fù)習(xí)講義:統(tǒng)編版選擇性必修2經(jīng)濟(jì)與社會生活
- 2025年憲法知識競賽試題庫及答案(共88題)
- 2025年升降機(jī)司機(jī)考試題題庫
- 2025年外研版高中英語選擇性必修第二冊Unit 6綜合檢測試卷及答案
- 2025年山西(行測)考試模擬試題(含答案)
- 2025上海市八年級升九年級數(shù)學(xué)暑假提升講義:三角形一邊的平行線(第1課時)(十大題型)解析版
- 2026高中語文必須要關(guān)注的七種高頻作文題型-2026年高考語文議論文寫作技巧
- 2025統(tǒng)編版初升高語文專項提升:文言句式(解析版)
- 硅PU球場施工方案模板
- 職高英語詞匯表優(yōu)質(zhì)資料
- YY/T 0752-2009電動骨組織手術(shù)設(shè)備
- 用人單位職業(yè)衛(wèi)生檔案(加油站)
- GB/T 40080-2021鋼管無損檢測用于確認(rèn)無縫和焊接鋼管(埋弧焊除外)水壓密實性的自動電磁檢測方法
- GB/T 2-2001緊固件外螺紋零件的末端
- 插花藝術(shù)全部講課稿課件
- 標(biāo)準(zhǔn)DBS54 2002-2017 食品安全地方標(biāo)準(zhǔn) 糌粑制作規(guī)范
- 教育評價學(xué)全套ppt課件完整版教學(xué)教程
- 油氣藏類型、典型的相圖特征和識別實例
- 未來教育家治校方略
評論
0/150
提交評論