Java 面向对象高级 继承

1. 继承

1.1 面向对象的三大特征

  1. 封装
    把离散的数据/行为封装成一个整体
  2. 继承
  3. 多态

1.2 什么是继承/继承有什么好处

  • 继承是类和类之间的父子关系, Java中提供关键字extends, 用于建立类与类之间的关系

eg:

定义了一个Student类, 继承Person类

java 复制代码
public class Student entends Person{
              子类             父类
            /派生类          /基类/超类
}
  • 好处:
    • 可以把多个子类中的重复代码抽取到父类中, 提高代码复用性
    • 子类可以在父类的基础上, 增加其他功能, 使子类强大

eg:

Person.java

java 复制代码
package oopextends.text1;  
  
public class Person {  
    String name;  
    int age;  
  
    public void eat(){  
        System.out.println("吃饭");  
    }  
}

Student.java

java 复制代码
package oopextends.text1;  
  
public class Student extends Person{  
  
    //子类特有的内容  
  
    //特有属性  
    String grade;  
  
    public void study(){  
        System.out.println("学生在学习");  
    }  
  
  
}

Teacher.java

java 复制代码
package oopextends.text1;  
  
public class Teacher extends Person{  
    //子类特有的内容  
  
    //特有属性  
    String subject;  
  
    public void teach(){  
        System.out.println("老师在教书");  
    }  
}

Text.java

java 复制代码
package oopextends.text1;  
  
public class Text {  
    static void main() {  
        Student s = new Student();  
        s.name = "张三";  
        s.age = 18;  
        s.grade = "高三";  
  
        s.study();  
        s.eat();  
  
        Teacher t = new Teacher();  
        t.name = "李四";  
        t.age = 35;  
        t.subject = "数学";  
  
        t.teach();  
        t.eat();  
  
    }  
}

1.3 如何设计继承结构

  • 当类与类之间, 存在形同(共性)的内容, 并满足子类是父类的一种, 就可以考虑使用继承, 来优化代码
  • 父类起名要能代表所有的子类

eg:

现在有三个电子设备, 请设计他们的继承结构

  • 安卓手机:
    • 属性: 品牌, 价格
    • 行为: 打电话, 发短信, nfc功能
  • 苹果手机:
    • 属性: 品牌, 价格
    • 行为: 打电话, 发短信
  • 笔记本电脑
    • 属性: 品牌, 价格
    • 行为: 编程

设计继承结构:

画图, 从下到上 -> 分类 -> 抽取共性的内容不断往上抽取(从下往上抽) -> 写代码(从下往上写)


1.4 继承的特点

  • IDEA中子类特有的是黑色加粗, 没有加粗的是父类的

  • Java只支持单继承 , 不支持多继承 , 但支持多层继承

    • 支持单继承: 一个子类只能继承一个父类
    • 不能多继承: 子类不能继承多个父亲
    • 多层继承:
      • 直接父类间接父类(没有爷类的概念)
      • 顶级父类Object(没有父类的父类默认为Object)

1.5 继承中成员的特点

1.5.1 成员变量的特点
  • 书写规则: 把多个子类中相同的属性抽取父亲当中(抽取共性)

  • 调用规则: 遵守就近原则

    • 就近原则: 谁离我近, 我就用谁

    • eg:

    注意: 最多到父类, 父类的父类就无法获取了

    注意: 本类没有也最高只能到第一个父类

1.5.2 成员方法的特点
  • 书写规则: 把多个子类中共性的成员方法抽取到父类中(抽取共性)

  • 调用规则: 遵守就近原则

  • 方法的重写: 在子类中, 把父类的方法再写一遍, 方法申明保持一致(方法的修饰符, 名字, 小括号内的参数列表 )

    • 使用场景: 如果父类的方法不能满足子类的要求了, 子类可以把方法再重写一边

    • 小技巧: Alt+Ins / Alt + Fn + Del 选择重写方法, 可自动生成重写方法, 或者直接输入想要重写的方法的名称,回车

    • 注意:

      • 如果父类里面的代码,我一行都不想用,此时把子类中的方法体重新完整写一遍即可(练习一)
      • 如果父类里面的代码我还想用,此时我只是在父类的基础上再加其他的逻辑此时可以先通过super关键字调用父类的方法得到一个结果,再对这个结果进行操作即可(练习二)
java 复制代码
package oopextends.text3;  
  
public class FirstGenerationPhone {  
  
    public void call(){  
        System.out.println("打电话");  
    }  
}
java 复制代码
package oopextends.text3;  
  
public class SecondGenerationPhone extends FirstGenerationPhone{  
    public void sendMessage(){  
        System.out.println("发短信");  
    }  
  
}
java 复制代码
package oopextends.text3;  
  
public class ThirdGenerationPhone extends SecondGenerationPhone{  
    //注释: 给程序员看的  
    //注解: 给虚拟机看的  
    @Override//注解  
    public void call() {  
        System.out.println("视频通话");  
    }  
	  
    public void playGame(){  
        System.out.println("玩游戏");  
    }  
}
java 复制代码
package oopextends.text3;  
  
public class Text {  
    static void main() {  
	  
        FirstGenerationPhone phone1 = new FirstGenerationPhone();  
        phone1.call();  
		  
        SecondGenerationPhone phone2 = new SecondGenerationPhone();  
        phone2.call();  
        phone2.sendMessage();  
		  
        ThirdGenerationPhone phone3 = new ThirdGenerationPhone();  
        phone3.call();  
        phone3.sendMessage();  
        phone3.playGame();  
    }  
  
}
java 复制代码
package oopextends.text4;  
  
public class SmartDevice {  
    //属性  
    String name;  
    double price;  
  
    //行为  
    public double payment(){  
        if(price >= 0 && price <= 1000){  
            return price ;  
        }else if(price > 1000 && price <= 5000){  
            return price * 0.9;  
        }else if(price > 5000 && price <= 10000){  
            return price * 0.8;  
        }else if(price > 10000){  
            return price * 0.7;  
        }else{  
            return 0;  
        }  
    }  
}
java 复制代码
package oopextends.text4;  
  
public class Phone extends SmartDevice{  
  
    @Override  
    public double payment() {  
        return super.payment()*0.9;  
    }  
}
java 复制代码
package oopextends.text4;  
  
public class Laptop extends SmartDevice{  
}
java 复制代码
package oopextends.text4;  
  
public class Pad extends SmartDevice {  
}
java 复制代码
package oopextends.text4;  
  
public class Text {  
    static void main() {  
        Phone p = new Phone();  
  
        p.name = "iphone";  
        p.price = 6000;  
  
        System.out.println(p.payment());  
  
  
        Laptop l = new Laptop();  
        l.name = "lenovo";  
        l.price = 8000;  
  
        System.out.println(l.payment());  
  
  
    }  
}
  • 方法重写的注意事项和要求:

    1. 重写方法的名称、形参列表必须与父类中的一致,方法体按照实际需求书写
    2. 了解: 子类重写父类方法时,访问权限子类必须大于等于父类(空着不写<protected<public)
    3. 了解: 子类重写父类方法时,返回值类型子类必须小于等于父类
    4. 建议: 重写方法的申明和父类保持一致
    5. final修饰类为最终类, 里面所有的方法不能被重写
    6. private私有方法, static静态方法, final最终方法不能被重写
  • 成员方法特点总结

  1. 继承中成员方法的特点:
    1. 书写规则: 抽取子类中的共性行为
    2. 调用规则: 就近原则
    3. this调用: 先访问本类, 再访问父亲
    4. super调用: 直接访问父亲
  2. 什么时方法重写?
    1. 在继承体系中, 子类出现了和父亲中一模一样的方法声明, 我们就称这个子类的这个方法是重写的方法
    2. 重写的方法要加上==@Override注解==, 校验重写的语法是否正确
  3. 什么时候用方法重写?
    当父类中的方法不能满足子类的要求, 需要进行方法的重写
  4. 重写方法有那些基本要求?
    1. 子类重写的方法申明跟父类保持一致
    2. private私有方法, static静态方法, final最终方法不能被重写
1.5.3 构造方法的特点
  • 父类中的构造方法不会被子类继承, 只能通过super关键字调用
    理解: 构造方法的方法名要与类名一致, 继承父类的名字就不一致了, 所以不能继承

小细节

  • 如果子类的构造方法未写super, JVM会加一个默认的super(), 先访问父类的无参构造
  • 要访问父类带参构造, super(参数)必须写上, 不能省略
  • 在创建对象的时候, 先执行父类的构造方法, 再执行子类的构造方法
  • 低版本super(参数)必须写在带参构造方法的第一行, 但新版本(jdk25)不用

tips

  • Alt+Ins / Alt + Fn + Del 用前面的方法也可以
java 复制代码
package oopextends.text5;  
  
public class Person {  
    //属性  
    String name;  
    int age;  
  
    //构造方法  
  
    public Person() {  
    }  
  
    public Person(String name, int age) {  
        this.name = name;  
        this.age = age;  
    }  
}
java 复制代码
package oopextends.text5;  
  
public class Student extends Person{  
    //属性  
    String grade;  
  
    //构造方法  
  
    public Student() {  
    }  
  
    public Student(String name, int age, String grade) {  
        super(name, age);  
        this.grade = grade;  
    }  
}
java 复制代码
package oopextends.text5;  
  
public class Teacher extends Person{  
    //属性  
    String subject;  
  
    //构造方法  
  
    public Teacher() {  
    }  
  
    public Teacher(String name, int age, String subject) {  
        super(name, age);  
        this.subject = subject;  
    }  
}
java 复制代码
package oopextends.text5;  
  
public class Text {  
    static void main() {  
        Student s = new Student("张三", 23, "高三");  
        System.out.println(s.name + " " + s.age + " " + s.grade);  
    }  
}

1.6 this关键字和super关键字

  • this内存角度: 表示当前方法的调用者的地址值

  • this代码角度: 利用this可以直接调用本类的成员(比如: 成员变量, 成员方法, 构造方法等)

  • super关键字: 代表使用父类中的内容

  • this(...) 访问本类的构造方法

    细节:

    若子类中有多个构造方法, 不能用this()互相调用, 一定要预留一个调用父类的构造方法

    若构造方法中写上了this(), 就不能再写super()了, JVM也不会自动添加super()


1.7 继承综合练习

1.7.1 学生老师

继承结构设计图:

java 复制代码
package oopextends.text7;  
  
public class Person {  
    //属性  
    private String name;  
    private int age;  
  
    //构造方法  
  
    public Person() {  
    }  
  
    public Person(String name, int age) {  
        this.name = name;  
        this.age = age;  
    }  
  
    //get/set  
  
    public String getName() {  
        return name;  
    }  
  
    public void setName(String name) {  
        this.name = name;  
    }  
  
    public int getAge() {  
        return age;  
    }  
  
    public void setAge(int age) {  
        this.age = age;  
    }  
  
    //行为  
    public void eat(){  
        System.out.println(name+"在吃饭");  
    }  
    public void sleep(){  
        System.out.println(name+"在睡觉");  
    }  
}
java 复制代码
package oopextends.text7;  
  
public class Student extends Person{  
    //属性  
    private String grade;  
  
  
    //构造方法  
  
    public Student() {  
    }  
  
    public Student(String name, int age, String grade) {  
        super(name, age);  
        this.grade = grade;  
    }  
  
    //get/set  
  
    public String getGrade() {  
        return grade;  
    }  
  
    public void setGrade(String grade) {  
        this.grade = grade;  
    }  
  
    //行为  
    public void study(){  
        System.out.println("学生正在学习");  
    }  
}
java 复制代码
package oopextends.text7;  
  
public class Teacher extends Person{  
    //属性  
    private String subject;  
  
    //构造方法  
  
    public Teacher() {  
    }  
  
    public Teacher(String name, int age, String subject) {  
        super(name, age);  
        this.subject = subject;  
    }  
  
    //get/set  
  
    public String getSubject() {  
        return subject;  
    }  
  
    public void setSubject(String subject) {  
        this.subject = subject;  
    }  
  
    //行为  
    public void teach(){  
        System.out.println("老师正在教书");  
    }  
}
java 复制代码
package oopextends.text7;  
  
public class BeachelorStudent extends Student{  
    //没有独有属性  
  
    //构造方法  
  
    public BeachelorStudent() {  
    }  
  
    public BeachelorStudent(String name, int age, String grade) {  
        super(name, age, grade);  
    }  
  
  
    //get/set 无属性, 不用写  
  
    //重写学习方法  
  
    @Override  
    public void study() {  
        System.out.println("本科同学正在攻读学士学位");  
    }  
}
java 复制代码
package oopextends.text7;  
  
public class MasterStudent extends Student{  
    //没有独有属性  
  
    //构造方法  
  
    public MasterStudent() {  
    }  
  
    public MasterStudent(String name, int age, String grade) {  
        super(name, age, grade);  
    }  
  
    //重写学习方法  
  
    @Override  
    public void study() {  
        System.out.println("硕士研究生同学正在攻读硕士学位");  
    }  
  
    //重写睡觉方法  
    @Override  
    public void sleep() {  
        System.out.println("硕士研究生住宿条件升级, 在豪华版学生公寓睡觉");  
    }  
}
java 复制代码
package oopextends.text7;  
  
public class MajorTeacher extends Teacher{  
    //没有独有属性  
  
    //构造方法  
  
    public MajorTeacher() {  
    }  
  
    public MajorTeacher(String name, int age, String grade) {  
        super(name, age, grade);  
    }  
  
    //重写学习方法  
  
    @Override  
    public void teach() {  
        System.out.println("专业教师正在教授专业知识");  
    }  
}
java 复制代码
package oopextends.text7;  
  
public class GeneralTeacher extends Teacher{  
    //没有独有属性  
  
    //构造方法  
  
    public GeneralTeacher() {  
    }  
  
    public GeneralTeacher(String name, int age, String grade) {  
        super(name, age, grade);  
    }  
  
    //重写学习方法  
  
    @Override  
    public void teach() {  
        System.out.println("通识课老师正在教授通识知识");  
    }  
}
java 复制代码
package oopextends.text7;  
  
public class Text {  
    static void main() {  
        BeachelorStudent bs = new BeachelorStudent("张三", 18, "大一");  
        System.out.println(bs.getName()+","+bs.getGrade()+","+bs.getAge());  
        bs.study();  
        bs.sleep();  
        bs.eat();  
  
        MasterStudent ms = new MasterStudent("李四", 20, "硕士");  
        System.out.println(ms.getName()+","+ms.getGrade()+","+ms.getAge());  
        ms.study();  
        ms.sleep();  
        ms.eat();  
  
        MajorTeacher mt = new MajorTeacher("王五", 35, "教授");  
        System.out.println(mt.getName()+","+mt.getSubject()+","+mt.getAge());  
        mt.teach();  
        mt.sleep();  
        mt.eat();  
  
        GeneralTeacher gt = new GeneralTeacher("赵六", 40, "副教授");  
        System.out.println(gt.getName()+","+gt.getSubject()+","+gt.getAge());  
        gt.teach();  
        gt.sleep();  
        gt.eat();  
  
    }  
}
1.7.2 黑马员工

继承结构设计图:

java 复制代码
package oopextends.text8;  
  
public class Employee {  
    //属性  
    private int id;  
    private String name;  
    private String job;  
  
    //构造方法  
  
    public Employee() {  
    }  
  
    public Employee(int id, String name, String job) {  
        this.id = id;  
        this.name = name;  
        this.job = job;  
    }  
  
    //set/get  
  
    public int getId() {  
        return id;  
    }  
  
    public void setId(int id) {  
        this.id = id;  
    }  
  
    public String getName() {  
        return name;  
    }  
  
    public void setName(String name) {  
        this.name = name;  
    }  
  
    public String getJob() {  
        return job;  
    }  
  
    public void setJob(String job) {  
        this.job = job;  
    }  
  
    //行为  
    public void work() {  
        System.out.println("员工正在工作");  
    }  
}
java 复制代码
package oopextends.text8;  
  
public class Teacher extends Employee{  
    //无特有属性  
  
    //构造方法  
    public Teacher() {  
    }  
  
    public Teacher(int id, String name, String job) {  
        super(id, name, job);  
    }  
  
    //无set/get  
  
    //无特殊行为  
}
java 复制代码
package oopextends.text8;  
  
public class AdminStaff extends Employee{  
    //无特有属性  
  
    //构造方法  
    public AdminStaff() {  
    }  
  
    public AdminStaff(int id, String name, String job) {  
        super(id, name, job);  
    }  
  
    //无set/get  
  
    //无特殊行为  
}
java 复制代码
package oopextends.text8;  
  
public class Lecturer extends Teacher{  
    //无特有属性  
  
    //构造方法  
    public Lecturer() {  
    }  
  
    public Lecturer(int id, String name, String job) {  
        super(id, name, job);  
    }  
  
    //无set/get  
  
    //重写工作  
  
    @Override  
    public void work() {  
        System.out.println("讲师正在授课");  
    }  
}
java 复制代码
package oopextends.text8;  
  
public class Maintainer extends AdminStaff{  
    //无特有属性  
  
    //构造方法  
    public Maintainer() {  
    }  
  
    public Maintainer(int id, String name, String job) {  
        super(id, name, job);  
    }  
  
    //无set/get  
  
    //重写工作  
    @Override  
    public void work() {  
        System.out.println("维护人员正在维护");  
    }  
}
java 复制代码
package oopextends.text8;  
  
public class Buyer extends AdminStaff{  
    //无特有属性  
  
    //构造方法  
    public Buyer() {  
    }  
  
    public Buyer(int id, String name, String job) {  
        super(id, name, job);  
    }  
  
    //无set/get  
  
    //重写工作  
    @Override  
    public void work() {  
        System.out.println("采购人员正在采购");  
    }  
}
java 复制代码
package oopextends.text8;  
  
public class Tutor extends Teacher{  
    //无特有属性  
  
    //构造方法  
    public Tutor() {  
    }  
  
    public Tutor(int id, String name, String job) {  
        super(id, name, job);  
    }  
  
    //无set/get  
  
    //重写工作  
    @Override  
    public void work() {  
        System.out.println("助教正在工作");  
    }  
}
java 复制代码
package oopextends.text8;  
  
public class Text {  
    public static void main(String[] args) {  
  
        Lecturer l = new Lecturer(1, "张三", "讲师");  
        l.work();  
  
        Maintainer m = new Maintainer(2, "李四", "维护人员");  
        m.work();  
  
        Tutor t = new Tutor(3, "王五", "助教");  
        t.work();  
  
        Buyer b = new Buyer(4, "赵六", "采购人员");  
        b.work();  
    }  
}
1.7.3 物流快递运费计算
java 复制代码
package oopextends.text9;  
  
public class Goods {  
    //属性  
    private String id;  
    private int weight;  
    private String name;  
  
    //构造方法  
  
    public Goods() {  
    }  
  
    public Goods(String id, int weight, String name) {  
        this.id = id;  
        this.weight = weight;  
        this.name = name;  
    }  
  
    //get/set  
  
    public String getId() {  
        return id;  
    }  
  
    public void setId(String id) {  
        this.id = id;  
    }  
  
    public int getWeight() {  
        return weight;  
    }  
  
    public void setWeight(int weight) {  
        this.weight = weight;  
    }  
  
    public String getName() {  
        return name;  
    }  
  
    public void setName(String name) {  
        this.name = name;  
    }  
  
    //行为  
    public int getPrice(){  
        return weight*10;  
    }  
}
java 复制代码
package oopextends.text9;  
  
public class SameCity extends Goods{  
    //无特殊属性  
  
    //构造方法  
  
    public SameCity() {  
    }  
  
    public SameCity(String id, int weight, String name) {  
        super(id, weight, name);  
    }  
  
    //无get/set  
  
    //重写快递费  
  
    @Override  
    public int getPrice() {  
        return super.getPrice()+10;  
    }  
}
java 复制代码
package oopextends.text9;  
  
public class AirSend extends Goods {  
    //无特殊属性  
  
    //构造方法  
  
    public AirSend() {  
    }  
  
    public AirSend(String id, int weight, String name){  
        super(id,weight,name);  
    }  
  
    //无get/set  
  
    //重写快递费  
    @Override  
    public int getPrice(){  
        return super.getPrice()+15;  
    }  
}
java 复制代码
package oopextends.text9;  
  
public class text {  
    public static void main(String[] args) {  
        SameCity sameCity = new SameCity("123", 10, "张三");  
        System.out.println(sameCity.getPrice());  
  
        AirSend airSend = new AirSend("123", 10, "李四");  
        System.out.println(airSend.getPrice());  
    }  
}

1.8 (扩展)继承的内存结构/字节码文件详解

1.8.1 继承的底层原理
  • 子类能调用≠子类能继承
1.8.2 子类真正能继承父类的东西
  1. 构造方法: 不能被子类继承, 可以用super关键字调用
  2. 成员变量: 可以被子类继承, private私有的也可以, 但是私有的无法直接调用
  3. 成员方法: 虚方法可以被继承(虚方法: 普通成员方法, 非final/static/private修饰的方法 )
    1. final修饰的最终方法不能被继承, 可以被调用
      编译期: 一级一级往上找, 遍历整个继承链, 确定要调用的方法在A类里, 记录该方法的地址
      运行期: 直接原型编译时确定的方法, 虽然降低了编译的速度, 但是运行的速度会得到保证
    2. static修饰的静态方法不能被继承, 可以被调用
      编译期: 一级一级的往上找, 遍历整个继承链, 确定要调用的方法在A里面, 将对象调用方法直接修改为类名的调用方法
      运行期: 直接运行
    3. private修饰的私有方法不能被继承, 不能被调用
    4. 方法重写: 子类替换虚方法表里方法的地址值
1.8.3 继承结构的内存图解

1.9 Java中的权限修饰符

  • 权限修饰符: 其实就是Java中的关键字, 用来控制一个成员被访问的范围
  • 修饰的内容: 可以修饰成员变量, 成员方法, 构造方法... 等
  • 作用范围从小到大(private<空着不写<protected<public)

相关推荐
云烟成雨TD1 小时前
Spring AI Alibaba 1.x 系列【37】ReactAgent 构建、执行流程分析
java·人工智能·spring
贵沫末1 小时前
Python——图像处理项目Conda环境搭建
开发语言·python·conda
白日梦想家6811 小时前
定时器实战避坑+高级用法,从入门到精通
开发语言·前端·javascript
white-persist1 小时前
逆向入门经典题:从 IDA 反编译坑点到 Python 解题详细分析解释
c语言·开发语言·数据结构·python·算法·逆向·安全架构
是宇写的啊2 小时前
MyBaties
java·开发语言·mybatis
钝挫力PROGRAMER2 小时前
程序中事件机制的实现
java·后端·python·软件工程
-凌凌漆-2 小时前
【Qt】const QString &与QString的区别
开发语言·qt
程序员威哥2 小时前
Java调用YOLO模型性能优化实战:CPU/GPU加速与内存优化全指南
java·人工智能·后端
Drone_xjw2 小时前
Qt QTableView 表头变白问题(Kylin/UKUI系统)原因分析与解决方案
开发语言·qt·kylin