2022/06/09 day09:继承、super、this

1. 继承

1.1 概述

由来:
多个类中存在相同属性和行为时,将这些内容抽取到单独一个类中,那么多个类无需再定义这些属性和行为,只要继承那一个类即可。

继承:就是子类继承父类的属性和行为,使得子类对象具有与父类相同的属性、相同的行为。子类可以直接访问父类中的非私有的属性和行为。

好处:

  1. 提高代码的复用性。
  2. 类与类之间产生了关系,是多态的前提。
    在这里插入图片描述

1.2 继承(子类与父类)的格式

在继承的关系中,“子类就是一个父类”。也就是说子类可以被当做父类看待。
例如父类是员工,子类是讲师,那么“讲师就是一个员工“,关系:is-a。

定义父类的格式:(一个普通的类定义)【就是一个普通的类】
public class 父类名称{
//…
}

定义子类的格式:【有区别】
public class 子类名称 extends 父类名称{

//…

}

例子:

package cn.itcast.day09.demo01;
//定义一个父类:员工
public class Employee {

    public void method(){

        System.out.println("方法执行!");
    }
}
package cn.itcast.day09.demo01;
//定义了一个员工的子类:讲师
public class Teacher extends Employee{
//空白的有东西吗?有,继承父类的
}

package cn.itcast.day09.demo01;
/*
定义了员工的另一个子类:助教
 */
public class Assistant extends Employee{

}
public class Demo01Extends {//Extends 继承 扩展

    public static void main(String[] args) {
        //创建了一个子类对象
        Teacher tea = new Teacher();

        //Teacher类中虽然什么都没有,但继承了来自父类的method().
        tea.method();

        //创建另一个子类助教的对象
        Assistant ass = new Assistant();
        ass.method();

    }
}

1.3 继承后的特定——成员变量

成员变量不重名:
如果子类父类中出现不重名的成员变量,这时的访问是没有影响的。

成员变量重名:
如果子类父类中出现重名的成员变量,这时的访问是有影响的。因为歧义出现了,一般优先使用本类当中的,没有再向上找。

在父子类的继承关系当中,如果成员变量重名,则创建子类对象时,访问有两种方式:
1. 直接通过子类对象访问成员变量:【直接访问】
用“." 等号左边是谁,就优先用谁【子类】,没有则向上找。
2. 间接通过成员方法访问成员变量:【间接访问】
该方法属于谁,就优先用谁,没有则向上找。属于父类,就会优先用父类的参数。

public class Fu {
    int numFu = 10;
    int num = 100;



    public void methodFu(){
        //使用的是本类当中的num,不会向下找
        System.out.println(num);
    }
}
public class Zi extends Fu{
    int numZi = 20;
    int num = 200;




    public void methodZi(){
        //因为本类当中有num,所以这里用的是本类的num【没有才往上找】
        System.out.println(num);
    }
}
public class Demo01ExtendsField {
    public static void main(String[] args) {
        Fu fu = new Fu();//创建父类对象
        System.out.println(fu.numFu);//只能使用父类的东西,没有任何子类的内容
        System.out.println("----------------------");

        Zi zi = new Zi();
        System.out.println(zi.numFu);//10
        System.out.println(zi.numZi);//20
        System.out.println("----------------------");

        //等号左边是谁,就优先用谁   Zi zi = new Zi();
        System.out.println(zi.num);//优先用子类:200
//        System.out.println(zi.abc);//到处都没有,报错
        System.out.println("----------------------");


        //这个方法是子类的,优先用子类的,没有再网上找。
        zi.methodZi();//200
        //这个方法是父类的,num值就优先用本类中的
        zi.methodFu();//100


    }
}

3个变量重名:

局部变量: 直接写成员变量名
本类的成员变量: this.成员变量名 【this 本类】
父类的成员变量: super.成员变量名 【super 父类】

public class Fu {
    int num =10;

}
public class Zi extends Fu{
    int num = 20;

    public void method(){

        int num = 30;

        System.out.println(num);//30   局部变量
        System.out.println(this.num);//20 本类调用【本类地址的成员变量】
        System.out.println(super.num);//10  父类的成员变量

    }
}
public class Demo01ExtendsField {
    public static void main(String[] args) {
        Zi zi = new Zi();
        zi.method();
    }
}

成员方法重名:
成员方法重名——重写

重写(Override)
概念:在继承关系当中,方法的名称一样,参数列表也一样。

重写(Override):方法的名称一样,参数列表【也一样】。一般也叫做:方法的覆盖、覆写。就称做【覆盖重写】也可以叫做【更新】见[覆盖重写的应用]
重载(Overload):方法的名称一样:参数列表【不一样】。
方法的覆盖重写特点:创建的是子类对象,则优先用子类方法。

在父子类的继承关系当中,创建子类对象,访问成员方法的规则:
创建的对象是谁,就优先用谁,如果没有则向上找

注意事项:
无论是成员方法还是成员变量,如果没有,都是向上找父类,绝对不会向下找子类的。

public class Fu {
    public void methodFu(){
        System.out.println("父类方法执行!");
    }

    public void method(){
        System.out.println("父类重名方法执行!");
    }
}
public class Zi extends Fu{
    public void methodZi(){
        System.out.println("子类方法执行!");
    }
    public void method(){
        System.out.println("子类重名方法执行!");
    }
}
public class Demo01ExtendsMethod {
    public static void main(String[] args) {
        Zi zi = new Zi();


        zi.methodFu();
        zi.methodZi();

        zi.method();
    }

}

方法覆盖重写的注意事项:

  1. 必须保证父子类之间方法的名称相同,参数列表也相同。
    @Override,写在方法面前,用来检测是不是有效的正确覆盖重写。@代表注解 annotation
    这个注解就算不写,只要满足要求,也是正确的方法覆盖重写,仅仅是一种安全检测手段。

  2. 子类方法的返回值必须【小于等于】父类方法的返回值范围。一般都是相等关系。
    小扩展提示:Object类是所有类的公共最高父类(祖宗类),位于继承关系的顶端,金字塔的塔尖。
    所以,java.long.String就是Object的子类。

3.修饰符就是权限:public private
子类方法的权限修饰符必须【大于等于】父类方法的权限修饰符。一般都是相等关系。
小扩展提示: public > protected > (default) > private
备注:(default)不是关键字default,而是什么都不写,留空。

对于方法来说,去掉修饰符:
一般方法(静态方法)还剩下:static 返回值类型 方法名(参数列表)
成员方法还剩下:返回值类型 方法名(参数列表)
构造方法还剩下:方法名(参数列表)//构造方法用于实体化对象而存在,就是一块空间,返回值没用,静态也没用
内存中先存在静态,后存在非静态。

注意事项:

  1. 子类方法覆盖父类方法,必须要保证权限大于等于父类权限。
  2. 子类方法覆盖父类方法,返回值类型、函数名和参数列表都要一模一样。

例子:

public class Fu {

      public Object method(){//【提问】方法不能用private吗?


        return null;
    }
}

public class Zi extends Fu{

    @Override  //覆盖重写:安全检查的作用
    public String method(){


        return null;
    }
}
public class Demo01Override {
    public int num;  //成员变量前用public
    protected int num1;//成员变量前用protected
    int num2;//留空默认就是(default)

}

覆盖重写的应用场景:
继承的来源:
在这里插入图片描述

例子:

/*
本来的老款手机
 */
public class Phone {
    public void call(){
        System.out.println("打电话!");
    }
    public void send(){
        System.out.println("发短信!");
    }
    public void show(){
        System.out.println("显示号码!");
    }
}
/*
定义一个新手机,使用老手机作为父类。
 */
public class NewPhone extends Phone {

    //打电话方法:call();继承
    //发端性方法:send();继承
    //关键是显示方法的更新:show()


    @Override   //在子类中直接打出方法名回车,会有提示
    public void show() {

//        System.out.println("显示号码!");//本来的功能
        // (可能代表100条代码)用【super关键字】调用父类方法
        //之所以用继承,就是为了解决重复代码的问题

        super.show();//把父类的show拿来重复利用
        //自己子类再来添加更多内容
        System.out.println("显示姓名!");//更新的功能
        System.out.println("显示头像!");//更新的功能
    }
}
public class Demo01Phone {
    public static void main(String[] args) {
        //老手机功能
        Phone phone = new Phone();
        phone.call();
        phone.send();
        phone.show();
        System.out.println("------------------------");


        //新手机功能
        NewPhone newPhone = new NewPhone();
        newPhone.call();
        newPhone.send();
        newPhone.show();
    }
}

1.4 父子类构造方法的访问特点

继承关系中,父子类构造方法的访问特点:
1.子类构造方法当中,有一个默认隐含的“super()”调用(无参构造),所以一定是先调用的父类构造,后执行的是子类构造。
2.可以通过super关键字在子类构造中调用父类重载构造。
3.super的父类构造调用,只能是子类构造方法中的【第一条】语句。不能一个子类构造调用多次super构造。【重要】
总结:
子类必须调用父类构造方法,不写则赠送super();写了则用指定的super调用。super只能有一个,还不必须是第一个。

public class Fu {
   public Fu(){
       System.out.println("父类无参构造!");
   }
   public Fu(int a){
       System.out.println("父类有参构造!");
   }


}
public class Zi extends Fu{
    public Zi(){
//        super();//编译器赠送的调用父类无参构造方法
        //如果父类构造方法有参数,那么是否还赠送呢?不再,那么怎么办?
        super(10);//在调用父类重载的构造方法。谁能对得上,就用谁。
        //使用了一个super之后,编译器将不再赠送super
        //因为super调用语句在构造方法中只能调用一次。所以只能选择其中一个调用。

        System.out.println("子类构造方法!");

    }

    public void method(){
//        super(); //错误写法,只有子类构造方法,才能调用父类构造方法。
    }
}
public class Demo01Constructor {
    public static void main(String[] args) {
        Zi zi = new Zi();//构造方法也会继承
        //先出的是父类的构造方法


       // Fu fu = new Fu();
    }
}

super关键字的典型用法:
super关键字的典型用法有三种:

  1. 在子类的成员方法中,访问父类的成员变量。
  2. 在子类的成员方法中,访问父类的成员方法。
  3. 在子类的构造方法中,访问父类的构造方法。

例子:

public class Fu {
    int num = 10;

    public Fu(){

    }


    public void method(){

        System.out.println("父类的成员方法method!");
    }

}
public class Zi extends Fu{
    int num = 20;

    public Zi(){
        super();//这条不写也默认有(编译器赠送)
    }

    public void methodZi(){
        System.out.println("本类中的num值:" + num);//本类中的num
        System.out.println("父类中的num值:" + super.num);//父类中的num
    }

    public void method(){
        super.method();//访问父类中的method
        System.out.println("子类中的成员方法method!");
    }
}

this的三种用法:

super和this的含义
super :代表父类的存储空间标识(可以理解为父亲的用)。
this :代表当前对象的引用(谁调用就代表谁)。

super关键字用来访问父类内容,而this关键字用来访问本类内容。
用法也有三种:

  1. 在本类的成员方法中,访问本类的成员变量。
  2. 在本类的成员方法中,访问本类的另一个成员方法。
  3. 在本类的构造方法中,访问本类另一个构造方法。
    在第三种用法中要注意:
    a. this(…)也必须是构造方法中的【第一条】语句。且只能有一个。此时默认的super()不再赠送。
    b. (谁是第一个?)super和this不能同时使用。
    c. 没使用this()的构造方法中默认存在调用父类无参构造的super()。

例子:

public class Fu {
    int num = 30;
}
public class Zi extends Fu{

    public Zi(){
//        this()//错误写法,自己调用自己了
        this(25);//调用了有参构造
        //构造方法的重载调用:本类中的无参构造,调用本类中的有参构造。
    }
    public Zi(int num){
        this.num = num; //这种设计图(类)中成员变量
    }

    int num = 20;//成员变量(全局变量)
    public void showNumber(){
        int num = 10;//局部变量
        System.out.println("访问本类局部变量:" + num);
        System.out.println("访问本类成员变量" + this.num);
        System.out.println("访问父类成员变量:" + super.num);
    }

    public void methodA(){
        System.out.println("AAA~");
    }
    public void methodB(){
        methodA();//可以这样访问
        this.methodA();//也可以这样访问,强调是本类成员方法的作用,
        System.out.println("BBB~");
    }
}

super与this关键字内存图解:

在这里插入图片描述

public class Fu {
    int num = 10;

    public void method(){
        System.out.println("父类方法!");
    }
}
public class Zi extends Fu{

    int num = 20;

    @Override//都知道只是覆盖重写;能写Override尽量都写。
    public void method() {
        super.method();//调用父类方法
        System.out.println("子类方法!");
    }

    public void show(){

        int num = 30;
        System.out.println("局部变量:" + num); //局部变量
        System.out.println("本类成员变量:" + this.num);//本类成员变量
        System.out.println("父类成员变量:" + super.num);//父类成员变量

    }
}
public class Demo {
    public static void main(String[] args) {
        Zi zi = new Zi();
        zi.show();
        System.out.println("-----------------");
        zi.method();
    }
}

继承的特点:
java语言中三个最为重要的继承相关的特点:
在这里插入图片描述

                                                                                 ——此文档为学习笔记!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值