阅读 38

面向对象进阶:继承,重写,构造器访问,成员访问,this&super

面向对象三大基本特征之二:继承

继承概述

  • 继承是类与类之间的一种关系

  • 多个类继承单独的某个类,多个类就可使用单独的这个类的属性和行为了;Java中子类更强大

  • 多个类称为子类(又称派生类),单独的这个类称为父类(又称基类,或超类)

  • 使用extends关键字实现继承:public  class  子类名  extends  父类名()

    public class Student extends People{}//表示Student类继承自People类
  • 使用继承的好处:提高代码复用,减少代码冗余,增强类的功能扩展性

  • 测试代码:

    package com.java.test;public class Student2 extends People {
    
        public void study() {
            System.out.println(getName() + "读书学习");
        }}

    package com.java.test;public class Teacher extends People {
    
        public void teach() {
            System.out.println(getName() + "教书育人");
        }}

    package com.java.test;public class People {
        private String name;
        private int age;
    
        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;
        }}

    package com.java.test;public class TestExtends {
        public static void main(String[] args) {
            Student2 student = new Student2();
            Teacher teacher = new Teacher();
            student.setName("徕卡");
            student.setAge(23);
            teacher.setName("哈苏");
            teacher.setAge(32);
            System.out.println(student.getName() + "\t" + student.getAge());
            System.out.println(teacher.getName() + "\t" + teacher.getAge());
    
            student.study();
            teacher.teach();
        }}

继承的设计规范,内存运行原理

继承设计规范

  • 子类们相同特征(共性属性,共性方法)放在父类中定义;子类独有的属性和行为应该定义在子类自己里面

    如果子类独有的属性,行为定义在父类中,会导致其他子类也会得到这些属性和行为,这不符合面向对象逻辑

内存运行原理

  • 首先加载主方法时会在堆内存中开辟空间,在空间中划分出一块父类空间(称为super)和一块子类空间(称为this)

  • image.png

继承的特点(面试热点)

  1. 子类可以继承父类的属性和行为,但是子类不能继承父类的构造器

    • 子类可以直接使用父类的静态成员(共享并非继承)

      静态的成员属于类本身,且静态只会加载一次,静态是属于父类的关系,即子类不能继承父类的静态成员,这种关系是父类向子类共享静态成员,子类可以共享访问使用静态成员,但是并非继承关系

    • 子类是否可以继承父类的静态成员(存在争议)

    • Java官方文档的解释:子类不能继承父类的私有成员,但是如果子类中公有的方法影响到了父类私有成员,那么私有成员是能够被子类使用的

    • 个人理解:当存在一个子类对象时,在内存空间上:子类对象继承的super中私有成员被继承但是无法直接访问

    • 子类有自己的构造器,父类构造器用于初始化父类对象

    • 子类是否可以继承父类私有的成员(存在争议)

      image.png

  2. Java是单继承模式,一个类只能继承一个直接父类

  3. Java不支持多继承,但是支持多层继承

  4. Java中所有的类都是Object类的子类

继承后:成员变量,成员方法的访问特点

  • 在子类方法中访问成员变量,成员方法时,满足:就近原则

    就近原则:

    • 先子类局部范围找

    • 然后子类成员范围找

    • 然后父类成员范围找,如果父类范围还没有找到则报错

  • 使用super关键字访问父类的成员

  • 当子类和父类中出现了同名的方法,会优先使用子类同名方法,此时要使用父类中的同名方法的办法是在子类中建立中转方法

  • 测试代码

    package com.java.test;public class ExtendsDemo {
        public static void main(String[] args) {
            Wolf w = new Wolf();
            System.out.println(w.name);
            w.showName();
            w.dance();  //触发子类的dance方法
            //  调用中转方法来触发父类的dance方法
            w.sing();
        }}class Animal {
        public String name = "触发父类";
    
        public void dance() {
            System.out.println("父类dance方法触发");
        }}class Wolf extends Animal {
        public String name = "触发子类";
    
        public void showName() {
            String name = "局部名称";
            System.out.println(name);   //  局部名称
            System.out.println(this.name);  //  触发子类
            System.out.println(super.name); //  触发父类
        }
    
        public void dance() {
            System.out.println("子类dance方法触发");
        }
    
        public void sing() {
            super.dance();  //sing为中转方法
        }}

继承后:方法重写

  • 在继承体系中,子类出现了和父类中一模一样的方法声明,我们称子类这个方法是重写的方法

  • 方法重写的应用场景:

    • 当子类需要父类的功能,但父类的该功能不完全满足自己的需求时

    • 子类可以重写父类中的方法

  • @Override重写注解:

    • 放在重写后的方法上,作为重写是否正确的校验注解

    • 加上该注解后如果重写错误,编译阶段会出现错误提示(例如方法名不一致时,可以防止运行的是新方法而不是重写)

    • 建议重写方法都加上@Override注解,代码安全,优雅!

  • 方法重写注意事项和要求

    • 重写方法的名称,形参列表必须与被重写方法的名称和参数列表一致

    • 私有方法被能重写(因为私有方法本身也不可以被访问)

    • 子类重写方法时,访问权限必须大于或等于父类

      按公开级别从大到小依次是:public > protected > 缺省

    • 子类不能重写父类的静态方法,如果重写会报错

      因为静态方法属于类,而重写的前提就是对被重写的方法拥有所有权,子类不曾拥有父类静态方法,所以对子类而言不存在对父类静态方法重写这个说法

  • 测试代码:

    package com.java.test;public class ReWrite {
        public void run() {
            System.out.println("跑步");
        }
    
        public void play() {
            System.out.println("打球");
        }
    
        public static void main(String[] args) {
            ReWrite2 re = new ReWrite2();
            re.run();
            re.play();
        }}class ReWrite2 extends ReWrite {
        @Override
        public void run() {
            super.run();    //重写时保留父类原方法中的功能
            System.out.println("马拉松");  //对父类中的方法进行重写
        }
    
        @Override
        public void play() {
            super.play();
            System.out.println("锦标赛");
        }}

继承后:子类构造器的特点

  • 子类中所有的构造器默认都会先访问父类中无参的构造器,再执行自己

    • 子类在初始化的时候,有可能会使用到父类中的数据,如果父类没有完成初始化,子类将无法使用父类的数据

    • 子类初始化之前,一定要调用父类构造器先完成父类数据空间的初始化

  • 如何调用父类构造器

    • 子类构造器的第一行语句默认都是:super(),不写也存在

  • 测试代码:

    package com.java.test;public class constructor {
        public static void main(String[] args) {
            worker w = new worker();
            /*
            父类构造器被触发
            子类构造器被触发
             */
    
        }}class boss {
        public boss() {
            System.out.println("父类构造器被触发");
        }}class worker extends boss {
        public worker() {
            super();    //默认的,写不写都有,默认就是找父类无参构造器
            System.out.println("子类构造器被触发");
        }}

继承后:子类构造器访问父类有参构造器

  • super调用父类有参构造器的作用:

    • 初始化继承自父类的数据

  • 父类中没有无参构造器,只有有参构造器,会出现什么情况

    • 报错,因为子类默认调用父类的无参构造器

  • 如何解决

    • 子类构造器中可以通过书写super(...),手动调用父类的有参构造器

  • 测试代码:

    package com.java.test;public class Constructor1 {
        public static void main(String[] args) {
            American a = new American("张三", 21, "男");
            System.out.println(a.getName());
            System.out.println(a.getAge());
            System.out.println(a.getSex());
        }}class English {
        private String name;
        private int age;
    
        // 有参构造器引发继承报错,选择了有参构造器时,建议加上无参构造器
        // 或者子类手动调用父类的有参构造器,即便如此,实际开发仍建议加上无参构造器
        public English(String name, int age) {
            this.name = name;
            this.age = age;
        }
    
        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;
        }}class American extends English {
        private String sex;
    
        // 手动调用父类的有参构造器
        public American(String name, int age, String sex) {
            super(name, age);
            this.sex = sex;
        }
    
        public String getSex() {
            return sex;
        }
    
        public void setSex(String sex) {
            this.sex = sex;
        }}

this,super使用总结

关键字访问成员变量访问成员方法访问构造方法
thisthis.成员变量
访问本类成员变量
this.成员方法
访问本类成员方法
this(...)
访问本类构造器
supersuper.成员变量
访问父类成员变量
super.成员方法
访问父类成员方法
super(...)
访问父类构造器
  • this:代表本类对象的引用

  • super:代表父类存储空间的标识

  • 对于this(...)访问本类构造器

    案例代码:

    pubic class Student{
        private String schoolName;
        private String name;
        
        public Student(String name){
            this(name, "奥利奥")
        }
        
        public Student(String name, String schoolName){
            this.name = name;
            this.schoolName = schoolName;
        }}
  • this(...)和super(...)使用注意点

    • 子类通过this(...)去调用本类的其他构造器,本类其他构造器会通过super手动调用父类的构造器,最终还是会调用父类构造器的

    • this和super都只能放在构造器的第一行,所以也就意味着二者不可以共存在一个构造器中



作者:每天起床都想摆
链接:https://www.jianshu.com/p/a518f2f61011


文章分类
代码人生
版权声明:本站是系统测试站点,无实际运营。本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 XXXXXXo@163.com 举报,一经查实,本站将立刻删除。
相关推荐