解决lombok的@Data注解无法打印继承的父类信息问题
作者:樘棣寂寂
问题场景
子类StudentResp继承父类PersonResp,子类也拥有了父类的属性。
给子类中继承的父类属性的赋值,但是打印了以后只会显示子类信息,父类信息不显示。
- 子类:学生类继承父类人员类
@Data
public class StudentResp extends PersonResp {
/**
* 学号
*/
private Integer studentId;
/**
* 成绩
*/
private Integer score;
}- 父类:人员类
@Data
public class PersonResp {
/**
* 姓名
*/
private String name;
/**
* 年龄
*/
private Integer age;
}代码中给子类以及继承的父类信息赋值然后打印
public static void main (String[] args) {
StudentResp studentResp = new StudentResp();
//学生子类赋值
studentResp.setStudentId(1000000000);
studentResp.setScore(92);
//父类赋值
studentResp.setName("风清扬");
studentResp.setAge(18);
//打印学生子类信息
System.out.println(studentResp);
}打印出来只有子类自己的属性,父类的属性没有出来

问题分析
单独获取子类中父类的信息(name跟age),观察打印看有没有值
public static void main (String[] args) {
StudentResp studentResp = new StudentResp();
//学生子类赋值
studentResp.setStudentId(1000000000);
studentResp.setScore(92);
//父类赋值
studentResp.setName("风清扬");
studentResp.setAge(18);
//打印父类信息
System.out.println("姓名:" + studentResp.getName());
System.out.println("年龄:" + studentResp.getAge());
}打印出来发现是有值的

确认了继承本身是没有问题的,继承的父类的值都可以给上,也能获取到,随后直接打开target对应目录下的StudentResp子类,观察编译后的代码
public class StudentResp extends PersonResp {
private Integer studentId;
private Integer score;
public StudentResp() {
}
public Integer getStudentId() {
return this.studentId;
}
public Integer getScore() {
return this.score;
}
public void setStudentId(final Integer studentId) {
this.studentId = studentId;
}
public void setScore(final Integer score) {
this.score = score;
}
public boolean equals(final Object o) {
if (o == this) {
return true;
} else if (!(o instanceof StudentResp)) {
return false;
} else {
StudentResp other = (StudentResp)o;
if (!other.canEqual(this)) {
return false;
} else {
Object this$studentId = this.getStudentId();
Object other$studentId = other.getStudentId();
if (this$studentId == null) {
if (other$studentId != null) {
return false;
}
} else if (!this$studentId.equals(other$studentId)) {
return false;
}
Object this$score = this.getScore();
Object other$score = other.getScore();
if (this$score == null) {
if (other$score != null) {
return false;
}
} else if (!this$score.equals(other$score)) {
return false;
}
return true;
}
}
}
protected boolean canEqual(final Object other) {
return other instanceof StudentResp;
}
public int hashCode() {
int PRIME = true;
int result = 1;
Object $studentId = this.getStudentId();
int result = result * 59 + ($studentId == null ? 43 : $studentId.hashCode());
Object $score = this.getScore();
result = result * 59 + ($score == null ? 43 : $score.hashCode());
return result;
}
public String toString() {
return "StudentResp(studentId=" + this.getStudentId() + ", score=" + this.getScore() + ")";
}
}看到这里,大多数同学应该已经定位到出现问题的原因了。
最后的toString()方法可以明确的看到这里只取了子类本身的两个属性,并没有去获取父类的属性。
问题原因
通过看编译后的代码可以得出@Data不会打印继承的父类信息是因为该注解本身作用域的问题,@Data注解在编译时会自动给实体类添加@Setter,@Getter,@ToString等方法。
但是@Data注解的作用域只在当前类中,所以最终打印的时候只会打印出当前类(子类)的信息。
即使子类拥有的是全属性,但是打印不会显示父类信息。
解决方式
本文介绍两种解决方案。
- 第一种:在子类上添加@ToString(callSuper = true)注解,该注解会将父类的属性跟子类的属性一起生成toString;
- 第二种:不使用@Data注解,使用@Setter,@Getter注解,在父类中重写toString()方法并用JSON的方式打印。
1.子类添加@ToString(callSuper = true)注解
@Data
@ToString(callSuper = true)
public class StudentResp extends PersonResp {
/**
* 学号
*/
private Integer studentId;
/**
* 成绩
*/
private Integer score;
}打印子类
public static void main (String[] args) {
StudentResp studentResp = new StudentResp();
//学生子类赋值
studentResp.setStudentId(1000000000);
studentResp.setScore(92);
//父类赋值
studentResp.setName("风清扬");
studentResp.setAge(18);
//学生子类
System.out.println(studentResp);
}结果可以看到父类信息

再看看target中子类编译后的代码
public class StudentResp extends PersonResp {
private Integer studentId;
private Integer score;
public StudentResp() {
}
public Integer getStudentId() {
return this.studentId;
}
public Integer getScore() {
return this.score;
}
public void setStudentId(final Integer studentId) {
this.studentId = studentId;
}
public void setScore(final Integer score) {
this.score = score;
}
public boolean equals(final Object o) {
if (o == this) {
return true;
} else if (!(o instanceof StudentResp)) {
return false;
} else {
StudentResp other = (StudentResp)o;
if (!other.canEqual(this)) {
return false;
} else {
Object this$studentId = this.getStudentId();
Object other$studentId = other.getStudentId();
if (this$studentId == null) {
if (other$studentId != null) {
return false;
}
} else if (!this$studentId.equals(other$studentId)) {
return false;
}
Object this$score = this.getScore();
Object other$score = other.getScore();
if (this$score == null) {
if (other$score != null) {
return false;
}
} else if (!this$score.equals(other$score)) {
return false;
}
return true;
}
}
}
protected boolean canEqual(final Object other) {
return other instanceof StudentResp;
}
public int hashCode() {
int PRIME = true;
int result = 1;
Object $studentId = this.getStudentId();
int result = result * 59 + ($studentId == null ? 43 : $studentId.hashCode());
Object $score = this.getScore();
result = result * 59 + ($score == null ? 43 : $score.hashCode());
return result;
}
public String toString() {
return "StudentResp(super=" + super.toString() + ", studentId=" + this.getStudentId() + ", score=" + this.getScore() + ")";
}
}可以明确的看到最后的toString()方法中多了一个super.toString()方法,将父类的信息打印出来
2.不使用@Data注解,使用@Setter,@Getter注解,在父类中重写toString()方法并用JSON的方式打印。
子类使用@Setter,@Getter注解
@Getter
@Setter
public class StudentResp extends PersonResp {
/**
* 学号
*/
private Integer studentId;
/**
* 成绩
*/
private Integer score;
}父类中重写toString()方法并用JSON的方式打印
@Data
public class PersonResp {
/**
* 姓名
*/
private String name;
/**
* 年龄
*/
private Integer age;
@Override
public String toString() {
return JSON.toJSONString(this);
}
}打印子类
public static void main (String[] args) {
StudentResp studentResp = new StudentResp();
//学生子类赋值
studentResp.setStudentId(1000000000);
studentResp.setScore(92);
//父类赋值
studentResp.setName("风清扬");
studentResp.setAge(18);
//学生子类
System.out.println(studentResp);
}结果也可以看到父类信息

总结
这个问题本身不算是个大问题,延伸出来更为重要的是我们解决问题的思路。因为从本质上来说属性本身都是存在的,只是没打印出来。
但是遇到这个问题的时候第一反应都是,明明继承了父类,为啥父类的值会没有,从而会带偏我们去解决问题方向,遇到此类问题,第一我们应该先确认问题的本质,到底有没有给上值,确认了已经给上值,就说明只是打印的问题,进而去编译后的代码中查看为啥没打印出来,最终定位到问题从而解决问题。
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。
