第八天:继承、super与this、抽象类

一.继承

(一)概述

多个类中存在相同属性和行为时,将这些内容抽取到单独一个类中,那么多个类无需再定义这些属性和行为,只要继承那一个类即可。其中,多个类可以称为\color{red}{子类},单独那一个类称为\color{red}{父类}、超类(superclass)或者基类。继承描述的是事物之间的所属关系,这种关系是:\color{red}{is-a}的关系。

继承主要解决的问题就是:\color{red}{共性抽取}

image.png
1.定义

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

2.优点
  • 提高代码的复用性。
  • 类与类之间产生了关系,是多态的前提。
3.继承关系当中的特点:
  • 子类可以拥有父类的内容
  • 子类还可以拥有自己专有的内容。

(二)继承的格式

通过 extends 关键字,可以声明一个子类继承另外一个父类,定义格式如下:

class 父类 {
  ...
}
class 子类 extends 父类 {
  ...
}

代码:

/*
 * 定义员工类Employee,做为父类
 */
class Employee {
    String name; // 定义name属性

    // 定义员工的工作方法
    public void work() {
        System.out.println("尽心尽力地工作");
    }
}

/*
 * 定义讲师类Teacher 继承 员工类Employee
 */
class Teacher extends Employee {
    // 定义一个打印name的方法
    public void printName() {
        System.out.println("name=" + name);
    }
}

/*
 * 定义测试类
 */
public class ExtendsTest1 {
    public static void main(String[] args) {
        // 创建一个讲师类对象
        Teacher t = new Teacher();
        // 为该员工类的name属性进行赋值
        t.name = "小明";
        // 调用该员工的printName()方法
        t.printName(); // name = 小明
        // 调用Teacher类继承来的work()方法
        t.work(); // 尽心尽力地工作
    }
}

运行结果:

image.png

(三)Java中继承的特点

  1. Java只支持单继承,不支持多继承。
  2. Java支持多级继承(继承体系)。
  3. 一个子类的直接父类是唯一的,但是一个父类可以拥有很多个子类。
Java继承的三个特点.png

(四)继承后的特性

1.父类与子类成员变量重名

在父子类的继承关系当中,如果成员变量重名,则创建子类对象时,访问有两种方式。
访问规则:

  • 直接通过子类对象访问成员变量:
    等号左边是谁,就优先用谁,没有则向上找。
  • 间接通过成员方法访问成员变量:
    该方法属于谁,就优先用谁,没有则向上找。

代码:

class Fu {
    // Fu中的成员变量。
    int num = 100;

    public void methodFu() {
        // 访问父类中的num
        System.out.println("methodFu: " + num);
    }
}

class Zi extends Fu {
    // Zi中的成员变量
    int num = 200;

    public void methodZi() {
        // 访问子类中的num
        System.out.println("methodZi: " + num);
    }
}

public class ExtendTest2 {
    public static void main(String[] args) {
        // 创建父类对象
        Fu fu = new Fu();
        // 创建子类对象
        Zi zi = new Zi();

        // 等号左边是谁,就优先用谁
        System.out.println("zi.num: "+zi.num); // 优先子类,200
        System.out.println("fu.num: "+fu.num); // 100

        // 该方法属于谁,就优先用谁
        zi.methodZi(); // 200
        zi.methodFu(); // 100
    }
}

运行结果:

image.png

小贴士:Fu 类中的成员变量是非私有的,子类中可以直接访问。若Fu 类中的成员变量私有了,子类是不能直接访问的。通常编码时,我们遵循封装的原则,使用private修饰成员变量,可以在父类中提供公共的getXxx方法和setXxx方法。

2.子类中的三种变量重名

代码:

class Fu {
    // Fu中的成员变量。
    int num = 10;

}

class Zi extends Fu {
    // Zi中的成员变量
    int num = 20;

    public void method() {
        int num = 30;
        // 访问局部变量num
        System.out.println("子类当中的局部变量: " + num);

        System.out.println("子类当中的成员变量 " + this.num);

        System.out.println("父类当中的成员变量: " + super.num);
    }
}

public class ExtendTest3 {
    public static void main(String[] args) {
        // 创建子类对象
        Zi zi = new Zi();
        zi.method();
    }
}

运行结果:

image.png
3.成员方法重名—重写(Override)

如果子类父类中出现重名的成员方法,这时的访问是一种特殊情况,叫做方法重写 (Override)。
访问规则:
看new的是谁,就优先用谁,没有则向上找。

  • 方法重写 :子类中出现与父类一模一样的方法时(返回值类型,方法名和参数列表都相同),会出现覆盖效果,也称为重写或者复写。声明不变,重新实现。
  • 重写(Override): 方法的名称一样,参数列表\color{red}{也一样}
  • 重载(Overload),:方法的名称一样,参数列表\color{red}{不一样}

代码:

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

class Zi extends Fu {
    //子类重写了父类的show方法
    @Override
    public void show() {
        System.out.println("子类show方法执行");
    }
}

public class OverrideTest1 {
    public static void main(String[] args) {
        Zi z = new Zi();
        // new的是Zi,子类中有show方法,只执行重写后的show方法
        z.show();
    }
}

运行结果:

image.png

方法重写的注意事项:

  • 必须保证父子类之间方法的名称相同,参数列表也相同。
  • \color{red}{@Override}:写在方法前面,用来检测是不是有效的正确覆盖重写。(这个注解就算不写,只要满足要求,也是正确的方法覆盖重写)
  • 子类方法的返回值和抛出异常的范围必须\color{red}{小于等于}父类方法的范围。(java. lang.object类是所有类的公共最高父类)
  • 子类方法的权限必须\color{red}{大于等于}父类方法的权限修饰符。(public > protected > (default) > private)

重写的应用:
子类可以根据需要,定义特定于自己的行为。既沿袭了父类的功能名称,又根据子类的需要重新实现父类方法,从而进行扩展增强。


方法覆盖重写的应用场景.png

代码:

// 手机类
class Phone {
    public void sendMessage() {
        System.out.println("发短信");
    }

    public void call() {
        System.out.println("打电话");
    }

    public void showNum() {
        System.out.println("来电显示号码");
    }
}

// 智能手机类
class NewPhone extends Phone {
    // 重写父类的来电显示号码功能,并增加自己的显示姓名和图片功能
    @Override
    public void showNum() {
        //调用父类已经存在的功能使用super
        super.showNum();

        //增加自己特有显示姓名和图片功能
        System.out.println("显示来电姓名");
        System.out.println("显示头像");
    }
}

public class ExtendsPhone {
    public static void main(String[] args) {
        // 创建子类对象
        NewPhone np = new NewPhone();
        // 调用父类继承而来的方法
        np.call();
        // 调用子类重写的方法
        np.showNum();
    }
}

运行结果:

image.png
4.继承后的特点—构造方法

继承关系中,父子类构造方法的访问特点:

  • 子类构造方法当中有一个默认隐含的super()调用,所以一定是先调用的父类构造,后执行的子类构造。
  • 子类构造可以通过super关键字来调用父类重载构造。
  • super的父类构造调用, 必须是子类构造方法的第一个语句。 不能一个子类构造调用多次super构造。

总结:
子类必须调用父类构造方法,不写则赠送super();写了则用写的指定的super调用,super只能有一个,还必须是第一个。

代码:

class Fu {
    Fu() {
        System.out.println("父类无参构造方法!");
    }

    Fu(int num) {
        System.out.println("父类有参构造方法!" + "num值为: " + num);
    }
}

class Zi extends Fu {
    Zi() {
        // super(); // 调用父类无参构造方法(默认赠送,可以不写)
        System.out.println("子类无参构造方法!");
    }

    Zi(int num) {
        super(10); // 调用父类有参构造方法
        System.out.println("子类有参构造方法!" + "num值为: " + num);
    }
}

public class ExtendsConstructor {
    public static void main(String[] args) {
        Zi one = new Zi();
        Zi two = new Zi(20);
    }
}

运行结果:

image.png

二.super与this关键字

(一)super和this的含义

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

(二)super关键字的三种用法:

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

在第三种用法当中要注意: .
使用super(...)调用父类构造方法必须是子类构造方法的第一个语句。

代码:

class Fu {
    int num = 10;

    Fu() {
        System.out.println("父类构造方法");
    }

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

class Zi extends Fu {
    int num = 20;

    Zi() {
        super(); // 访问父类的构造方法
        System.out.println("子类构造方法");
    }

    @Override
    public void method() {
        System.out.println("父类num值: " + super.num); // 访问父类的成员变量num
        System.out.println("子类num值: " + num);
        super.method(); // 访问父类的成员方法method
        System.out.println("子类method方法!");
    }
}

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

运行结果:

image.png

(三)this关键字的三种用法

  1. 在本类的成员方法中,访问本类的成员变量。
  2. 在本类的成员方法中,访问本类的另一个成员方法。
  3. 在本类的构造方法中,访问本类的另一个构造方法。

在第三种用法当中要注意: .
使用this(...)调用其它构造方法必须是此构造方法的第一个语句。

代码:

class Fu {
    int num = 10;
}

class Zi extends Fu {
    int num = 20;

    public Zi() {
        this(123); // 访问本类的另一个构造方法
        System.out.println("无参构造方法执行!");
    }

    public Zi(int n) {
        System.out.println("有参构造方法执行!");
    }

    public void showNum() {
        int num = 30;
        System.out.println("局部变量num值:" + num);
        System.out.println("本类当中成员变量num值:" + this.num); // 访问本类的成员变量
    }

    public void MethodA() {
        System.out.println("成员方法MethodA执行!");
    }

    public void MethodB() {
        this.MethodA(); // 访问本类的另一个成员方法,this可以省略
        System.out.println("成员方法MethodB执行!");
    }
}

public class ThisExtends {
    public static void main(String[] args) {
        Zi zi = new Zi();
        zi.showNum();
        zi.MethodB();
    }
}

运行结果:

image.png

小提示:super() 和 this() 都必须是在构造方法的第一行,所以不能同时出现

(四)内存图

super与this的内存图.png

三.抽象类

(一)概述

父类中的方法,被它的子类们重写,子类各自的实现都不尽相同。那么父类的方法声明和方法主体,只有\color{red}{声明}还有意义,而\color{red}{方法主体}则没有存在的意义了。我们把没有方法主体的方法称为抽象方法。Java语法规定,\color{red}{包含}抽象方法的类就是抽象类。

抽象的概念.png

(二)定义

  • 抽象方法:没有方法体的方法。
  • 抽象类:包含抽象方法的类。

(三)abstract使用格式

1.抽象方法

使用abstract关键字修饰方法,该方法就成了抽象方法,抽象方法只包含一个方法名,而没有方法体。

  • 定义格式:修饰符 abstract 返回值类型 方法名 (参数列表);
  • 代码举例:public abstract void run();
2.抽象类

如果一个类包含抽象方法,那么该类必须是抽象类。

  • 定义格式:abstract class 类名字 {}
  • 代码举例:
public abstract class Animal {
  public abstract void run();
}

(四)如何使用抽象类和抽象方法:

  1. 不能直接创建new抽象类对象。
  2. 必须用一个子类来继承抽象父类。
    重写(\color{red}{实现}):子类去掉抽象方法的abstract关键字,然后补上方法体大括号。
  3. 子类必须重写抽象父类当中所有的抽象方法。
  4. 创建子类对象进行使用

此时的方法重写,是子类对父类抽象方法的完成实现,我们将这种方法重写的操作,也叫做实现方法。

代码:

abstract class Animal {
    public abstract void eat();
}

class Cat extends Animal {
    @Override
    public void eat() {
        System.out.println("猫吃鱼!");
    }
}

public class AbstractTest {
    public static void main(String[] args) {
        Cat cat = new Cat();
        cat.eat();
    }
}

运行结果:

image.png

(五)注意事项

  1. 抽象类不能创建对象,如果创建,编译无法通过而报错。只能创建其非抽象子类的对象。

理解:假设创建了抽象类的对象,调用抽象的方法,而抽象方法没有具体的方法体,没有意义。

  1. 抽象类中,可以有构造方法,是供子类创建对象时,初始化父类成员使用的。

理解:子类的构造方法中,有默认的super(),需要访问父类构造方法。

  1. 抽象类中,不一定包含抽象方法,但是有抽象方法的类必定是抽象类。

理解:未包含抽象方法的抽象类,目的就是不想让调用者创建该类对象,通常用于某些特殊的类结构设计(适配器模式)。

  1. 抽象类的子类,必须重写抽象父类中所有的抽象方法,否则,编译无法通过而报错。除非该子类也是抽象类。

理解:假设不重写所有抽象方法,则类中可能包含抽象方法。那么创建对象后,调用抽象的方法,没有意义。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,837评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,551评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,417评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,448评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,524评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,554评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,569评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,316评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,766评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,077评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,240评论 1 343
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,912评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,560评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,176评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,425评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,114评论 2 366
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,114评论 2 352

推荐阅读更多精彩内容