java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > lombok的@Data注解无法打印继承的父类信息

解决lombok的@Data注解无法打印继承的父类信息问题

作者:樘棣寂寂

在Java编程中,使用@Data注解可能导致子类继承父类属性后,打印只显示子类信息不显示父类信息,问题源于@Data注解作用域仅限于当前类,解决方法包括使用@ToString(callSuper=true)注解或重写toString方法

问题场景

子类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注解的作用域只在当前类中,所以最终打印的时候只会打印出当前类(子类)的信息。

即使子类拥有的是全属性,但是打印不会显示父类信息。

解决方式

本文介绍两种解决方案。

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

    }

结果也可以看到父类信息

总结

这个问题本身不算是个大问题,延伸出来更为重要的是我们解决问题的思路。因为从本质上来说属性本身都是存在的,只是没打印出来。

但是遇到这个问题的时候第一反应都是,明明继承了父类,为啥父类的值会没有,从而会带偏我们去解决问题方向,遇到此类问题,第一我们应该先确认问题的本质,到底有没有给上值,确认了已经给上值,就说明只是打印的问题,进而去编译后的代码中查看为啥没打印出来,最终定位到问题从而解决问题。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

您可能感兴趣的文章:
阅读全文