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

 更新时间:2024年11月06日 09:24:04   作者:樘棣寂寂  
在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注解的作用域只在当前类中,所以最终打印的时候只会打印出当前类(子类)的信息。

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

解决方式

本文介绍两种解决方案。

  • 第一种:在子类上添加@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);

    }

结果也可以看到父类信息

总结

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

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

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

相关文章

  • java中lambda(函数式编程)一行解决foreach循环问题

    java中lambda(函数式编程)一行解决foreach循环问题

    这篇文章主要介绍了java中lambda(函数式编程)一行解决foreach循环问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-07-07
  • SpringBoot 入门教程之引入数据传输层的方法

    SpringBoot 入门教程之引入数据传输层的方法

    这篇文章主要介绍了SpringBoot 入门教程之引入数据传输层的方法,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-07-07
  • @ControllerAdvice 用法解析

    @ControllerAdvice 用法解析

    @ControllerAdvice就是@Controller 的增强版,@ControllerAdvice主要用来处理全局数据,一般搭配@ExceptionHandler、@ModelAttribute以及@InitBinder使用,这篇文章主要介绍了@ControllerAdvice 用法,需要的朋友可以参考下
    2022-11-11
  • Character.UnicodeBlock中cjk的说明详解

    Character.UnicodeBlock中cjk的说明详解

    这篇文章主要为大家详细介绍了Character.UnicodeBlock中cjk的说明,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-09-09
  • spring的jdbctemplate的crud的基类dao

    spring的jdbctemplate的crud的基类dao

    本文主要介绍了使用spring的jdbctemplate进行增删改查的基类Dao的简单写法,需要的朋友可以参考下
    2014-02-02
  • Java多线程之线程安全问题详细解析

    Java多线程之线程安全问题详细解析

    这篇文章主要给大家介绍了关于Java多线程之线程安全问题的相关资料,Java多线程中线程安全问题是一个常见的问题,因为多个线程可能同时访问共享的资源,文中通过图文介绍的非常详细,需要的朋友可以参考下
    2023-11-11
  • Java中的事件处理机制详细解读

    Java中的事件处理机制详细解读

    这篇文章主要介绍了Java中的事件处理机制详细解读,ava事件处理是采取"委派事件模型",当事件发生时,产生事件的对象会把此"信息"传递给"事件的监听者"处理,需要的朋友可以参考下
    2024-01-01
  • Springboot整合Swagger3全注解配置(springdoc-openapi-ui)

    Springboot整合Swagger3全注解配置(springdoc-openapi-ui)

    本文主要介绍了Springboot整合Swagger3全注解配置(springdoc-openapi-ui),文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-03-03
  • Idea创建多模块maven聚合项目的实现

    Idea创建多模块maven聚合项目的实现

    这篇文章主要介绍了Idea创建多模块maven聚合项目的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-12-12
  • springboot如何集成Swagger2

    springboot如何集成Swagger2

    这篇文章主要介绍了springboot集成Swagger2的方法,帮助大家更好的理解和使用springboot框架,感兴趣的朋友可以了解下
    2020-12-12

最新评论