在java虛擬機規範中,虛擬機棧和本地方法棧都會出現StackOverflowError和OutofMemoryError,程序計數器是java虛擬機中唯一一塊不會產生error的內存區域,StackOverflowError代表的是,當棧深度超過虛擬機分配給線程的棧大小時就會出現此error,OutofMemoryError代表的是,當再申請新的內存時,虛擬機分配給線程的內存大小中無法再分配新的內存,就會出現此error。
現象:對象互相嵌套設置出現StackOverflowError異常
對象A:
package com.test; import com.wordnik.swagger.annotations.ApiModel; import com.wordnik.swagger.annotations.ApiModelProperty; import java.io.Serializable; import java.util.List; /** * test-manager * Created by xian.juanjuan on 2017-5-11 16:25. */ @ApiModel(description = "test-manager Created by xian.juanjuan on 2017-5-11 16:25.") public class Student implements Serializable{ private static final long serialVersionUID = -4895104060364320456L; /** * 用戶ID */ @ApiModelProperty(value = "用戶ID") private String userId; /** * 用戶名 */ @ApiModelProperty(value = "用戶名") private String userName; /** * 分數 */ @ApiModelProperty(value = "分數") private List<Score> scores; /** * 獲取 用戶ID */ public String getUserId() { return this.userId; } /** * 設置 用戶ID */ public void setUserId(String userId) { this.userId = userId; } /** * 獲取 用戶名 */ public String getUserName() { return this.userName; } /** * 設置 用戶名 */ public void setUserName(String userName) { this.userName = userName; } /** * 獲取 分數 */ public List<Score> getScores() { return this.scores; } /** * 設置 分數 */ public void setScores(List<Score> scores) { this.scores = scores; } }
對象B:
package com.test; import com.wordnik.swagger.annotations.ApiModel; import com.wordnik.swagger.annotations.ApiModelProperty; import java.io.Serializable; /** * test-manager * Created by xian.juanjuan on 2017-5-11 16:25. */ @ApiModel(description = "test-manager Created by xian.juanjuan on 2017-5-11 16:25.") public class Score implements Serializable { private static final long serialVersionUID = -6345327076401038020L; /** * 分數 */ @ApiModelProperty(value = "分數") private String subject; /** * 科目 */ @ApiModelProperty(value = "科目") private double score; /** * 學生信息 */ @ApiModelProperty(value = "學生信息") private Student student; /** * 獲取 分數 */ public String getSubject() { return this.subject; } /** * 設置 分數 */ public void setSubject(String subject) { this.subject = subject; } /** * 獲取 科目 */ public double getScore() { return this.score; } /** * 設置 科目 */ public void setScore(double score) { this.score = score; } /** * 獲取 學生信息 */ public Student getStudent() { return this.student; } /** * 設置 學生信息 */ public void setStudent(Student student) { this.student = student; } }
測試
package com.test; import com.alibaba.fastjson.JSONObject; import java.util.ArrayList; import java.util.List; /** * test-manager * Created by xian.juanjuan on 2017-5-11 16:25. */ public class Test { public static void main(String[] args){ Student student = new Student(); student.setUserId("001"); student.setUserName("小神經"); Score score = new Score(); score.setSubject("語文"); score.setScore(100); score.setStudent(student); // TODO score入庫 List<Score> scores = new ArrayList<>(); scores.add(score); student.setScores(scores); //TODO student入庫 System.out.print("運行完畢,學生信息爲:"+ JSONObject.toJSONString(student)); } }
運行結果:
"C:\Program Files\Java\jdk1.8.0_71\bin\java" -Didea.launcher.port=7532 "-Didea.launcher.bin.path=D:\soft\IntelliJ IDEA 2016.1.1\bin" -classpath C:\Users\xian.juanjuan\AppData\Local\Temp\classpath92.jar -Dfile.encoding=UTF-8 com.intellij.rt.execution.application.AppMain
com.jyall.goods.product.service.Test
運行完畢,學生信息爲:{"scores":[{"score":100,"student":{"$ref":"$"},"subject":"語文"}],"userId":"001","userName":"小神經"}
Process finished with exit code 0
debug看運行過程中的參數信息:
score和student之間出現循環賦值,如果這裏的對象屬性比較多的時候,這種循環調用之後會導致該線程的堆棧異常,最終導致StackOverflowError異常;如何避免這種情況發生呢?可以克隆或者新建對象:
例如:
package com.jyall.goods.product.service; import com.alibaba.fastjson.JSONObject; import org.springframework.beans.BeanUtils; import java.util.ArrayList; import java.util.List; /** * goods-main-manager * Created by xian.juanjuan on 2017-5-11 16:25. */ public class Test { public static void main(String[] args){ Student student = new Student(); student.setUserId("001"); student.setUserName("小神經"); Score score = new Score(); score.setSubject("語文"); score.setScore(100); //避免循環調用出現StackOverflowError異常,這裏用臨時對象studentTemp Student studentTemp = new Student(); BeanUtils.copyProperties(student,studentTemp); score.setStudent(studentTemp); // TODO score入庫 List<Score> scores = new ArrayList<>(); scores.add(score); student.setScores(scores); //TODO student入庫 System.out.print("運行完畢,學生信息爲:"+ JSONObject.toJSONString(student)); } }互相嵌套過程中不會出現死循環現象~