在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));
}
}