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