Java 互相關聯的實體無限遞歸問題的解決
Java 互相關聯的實體無限遞歸
今天在測試的時候出現瞭一個bug,在把關聯實體序列化返回的過程中報錯瞭,提示
Caused by: java.lang.StackOverflowError: null
這個是堆棧溢出錯誤,根據錯誤線索查找,最後發現Column和Table實體互相關聯,也就是說
Column實體中有Table屬性,Table實體中也有Column屬性,導致瞭在序列化的過程中出現瞭死循環,無限遞歸,以至堆棧溢出報錯。
在Jackson2.0以前的解決辦法是
在關聯的屬性上添加
@JsonBackReference
或者
@JsonIgnore
註解中的一個即可。但是從Jackson2.0以後的版本開始,提供@JsonIdentityInfo註解實現這個問題的解決,在實體類前加註解
@JsonIdentityInfo(generator=ObjectIdGenerators.IntSequenceGenerator.class, property="@id")
好好理解Java中的遞歸
遞歸的思想
把規模大的問題轉化為規模小的相似的子問題來解決。在函數實現時,因為解決大問題的方法和解決小問題的方法往往是同一個方法,所以就產生瞭函數調用它自身的情況。另外這個解決問題的函數必須有明顯的結束條件,這樣就不會產生無限遞歸的情況瞭。
一句話總結:遞歸就是自己調用自己。
遞歸的條件要素
1、遞歸有兩個重要條件
- 可以通過遞歸調用來縮小問題規模,且新問題與原問題有著相同的形式。(自身調用)
- 存在一種簡單情境,可以使遞歸在簡單情境下退出。(遞歸出口)
2、遞歸的三要素
- 嘗試將一個問題化簡到更小的規模
- 父問題與子問題不能有重疊的部分
- 一定有一種可以退出程序的情況
遞歸的算法結構
遞歸的常用算法偽代碼如下:
func( mode){ if(endCondition){ //遞歸出口 end; }else{ func(mode_small) //調用本身,遞歸 } }
遞歸實戰舉例
遞歸講起來還是有點小抽象,我們直接來看代碼
1、斐波那契數的遞歸實現
斐波那契數列的遞推公式:Fib(n)=Fib(n-1)+Fib(n-2),生成數列(1、1、2、3、5、8…)。
public static int fib(int n) throws Exception { if (n < 0){ throw new Exception("請輸入正確的參數"); } else if (n == 0 || n == 1){ return n; } else { return fib(n - 1) + fib(n - 2); // 調用自己 } }
2、99乘法表的遞歸實現
public static void mul(int n){ if(n==1){ System.out.println("1*1=1"); }else { mul(n -1); for(int i=1;i<=n;i++){ System.out.println(i + "*" + n + "=" + i*n + " "); } } }
小結一下吧
遞歸算法是一種直接或間接地調用自身的算法。如果一個問題可以解可以分解為幾個子問題的解; 這個問題與分解之後的子問題,除瞭數據規模不同,求解思路完全一樣;並且存在明顯的遞歸終止條件;那麼遞歸將是一種不錯的選擇。
以上為個人經驗,希望能給大傢一個參考,也希望大傢多多支持WalkonNet。
推薦閱讀:
- java 異常之手動拋出與自動拋出的實例講解
- java自定義異常以及throw和throws關鍵字用法
- 簡述Java中throw-throws異常拋出
- 一篇文章看懂Java異常處理
- Java catch與throw同時使用的操作