Java篇之继承

目录

[一. 继承](#一. 继承)

[1. 为什么需要继承](#1. 为什么需要继承)

[2. 继承的概念](#2. 继承的概念)

[3. 继承的语法](#3. 继承的语法)

[4. 访问父类成员](#4. 访问父类成员)

[4.1 子类中访问父类的成员变量](#4.1 子类中访问父类的成员变量)

[4.2 子类中访问父类的成员方法](#4.2 子类中访问父类的成员方法)

[5. super关键字](#5. super关键字)

[6. super和this关键字](#6. super和this关键字)

[7. 子类构造方法](#7. 子类构造方法)

[8. 代码块的执行顺序](#8. 代码块的执行顺序)

[9. protected访问修饰限定符](#9. protected访问修饰限定符)

[10. 继承方式](#10. 继承方式)

11.final关键字

[12. 继承与组合](#12. 继承与组合)

结语


一. 继承

1. 为什么需要继承

在Java中类是对现实生活中一组对象的抽象描述,是创建对象的模板,经过实例化后的对象可以用来表示现实中的实体,但是我们可以发现很多事物是存在一些关联的,比如:永劫无间中的治疗型英雄和进攻性英雄、他们都是英雄角色

用我们的Java语言该如何实例化一个永劫无间中的英雄对象呢

public class Therapeutic {//治疗型
    public String name ;//表示名字
    public int age;//表示年龄
    public int HP;//表示血量

    public Therapeutic(String name, int age, int HP) {
        this.name = name;
        this.age = age;
        this.HP = HP;
    }

    public void run(){
        System.out.println(this.name +"正在跑...");
    }
    public void used_Treatskill()
    {
        System.out.println(this.name+"使用了治疗技能...");
    }
}



public class Offensive {//进攻型
    public String name ;//表示名字
    public int age;//表示年龄
    public int HP;//表示血量

    public Offensive(String name, int age, int HP) {
        this.name = name;
        this.age = age;
        this.HP = HP;
    }

    public void run(){
        System.out.println(this.name +"正在跑...");
    }
    public void used_Offensive_skill()
    {
        System.out.println(this.name+"使用了进攻技能...");
    }
}

通过上述代码我们可以发现,在我们的进攻型英雄和治疗型英雄的中存在大量的重复代码,如图所示:

那么有什么办法能够将这些共性抽取,来减少代码的冗余和增加代码的复用性呢?那么在我们面向对象的思想中提出了继承的概念,专门用来进行共性抽取,实现代码复用。

2. 继承的概念

在Java中,继承是面向对象编程的重要特性之一,它允许一个类(子类)继承另一个类(父类)的属性和方法,从而减少代码的冗余和实现代码的复用,继承主要解决的问题就是:共性的抽取,实现代码复用。

例如上述说的:治疗型英雄和进攻型英雄都是英雄人物,那么我们可以将共性的内容进行抽取。

3. 继承的语法

在实现上述例子继承关系之前,我们先来学习一下继承的语法。在Java中要实现类之间的继承关系,我们需要借助extends关键字:

修饰符 class 子类 extends 父类 {
    内容
    // ... 
}

那么对于上述例子我们就可以重新设计:

//英雄类
public class Heroic_Characters {
    public String name ;//表示名字
    public int age;//表示年龄
    public int HP;//表示血量

    public Heroic_Characters(String name, int age, int HP) {
        this.name = name;
        this.age = age;
        this.HP = HP;
    }

    public void run(){
        System.out.println(this.name +"正在跑...");
    }
}

//治疗型英雄类
public class Therapeutic extends Heroic_Characters {

    public Therapeutic(String name, int age, int HP) {
        super(name, age, HP);
    }//治疗型

    public void used_Treatskill()
    {
        System.out.println(this.name+"使用了治疗技能...");
    }
}
//进攻型英雄类
public class Offensive extends Heroic_Characters{

    public Offensive(String name, int age, int HP) {
        super(name, age, HP);
    }//进攻型

    public void used_Offensive_skill()
    {
        System.out.println(this.name+"使用了进攻技能...");
    }
}
  • 继承后。子类会继承父类中的成员变量和成员方法
  • 如果子类和父类的成员变量、成员属性都相同。那么继承就变得没有意义,所以子类继承父类后,需要有自己特有的成员或者方法,体现出与父类的不同。

4. 访问父类成员

子类继承父类之后,在子类中我们能否直接访问从父类继承下来的成员呢?

此时我们分为两种情况:

  1. 子类中访问父类的成员变量
    1. 子类和父类中不存在同名的成员变量
    2. 子类和父类中存在同名的成员变量
  2. 子类访问父类中的成员方法
    1. 成员方法名字不同
    2. 成员方法名字相同

4.1 子类中访问父类的成员变量

1.子类和父类中不存在同名的成员变量

2.子类和父类中存在同名的成员变量

**总结:**在子类访问成员变量时,如果访问的成员变量在子类中存在,那么优先访问子类自己的成员变量,如果子类没有再去父类中找,如果子类和父类都没有,那么就会报错。

4.2 子类中访问父类的成员方法

1.成员方法名字不同

2.成员方法名字相同

总结:当子类成员方法和父类成员方法名字相同时,优先从子类中找,如果子类没有就去父类找。都找不到则进行报错处理。

那么如果我想在子类和父类成员变量或成员方法相同的情况下,访问父类的成员该怎么办呢?

5. super关键字

当我想实现上述的情况时,这时候就要引入Java中提供的关键字super来解决:该关键字的作用就是在子类方法中访问父类的成员。

在子类方法中,想要明确访问父类中的成员变量和方法,借助super关键字就好啦,但是super只能在非静态方法中使用。

6. super和this关键字

|-------|-------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| | 相同点 | 不同点 |
| super | 1. 都是Java中的关键字 2. 只能在非静态方法中使用,访问非静态的成员 3.在构造方法中调用时,必须是第一条语句 | 1.this表示的是当前对象的引用,supe表示的是从父类继承下来的部分成员的引用 2. 在非静态成员方法中, this 用来访问本类的方法和属性, super 用来访问父类继承下来的方法和属性 3. 在构造方法中: this( ) 用于调用本类构造方法, super( ) 用于调用父类构造方法,两种调用不能同时在构造 方法中出现 4. 构造方法中一定会存在 super(...) 的调用,用户没有写编译器也会增加,但是 this(...) 用户不写则没有 |
| this | 1. 都是Java中的关键字 2. 只能在非静态方法中使用,访问非静态的成员 3.在构造方法中调用时,必须是第一条语句 | 1.this表示的是当前对象的引用,supe表示的是从父类继承下来的部分成员的引用 2. 在非静态成员方法中, this 用来访问本类的方法和属性, super 用来访问父类继承下来的方法和属性 3. 在构造方法中: this( ) 用于调用本类构造方法, super( ) 用于调用父类构造方法,两种调用不能同时在构造 方法中出现 4. 构造方法中一定会存在 super(...) 的调用,用户没有写编译器也会增加,但是 this(...) 用户不写则没有 |

7. 子类构造方法

当我们子类对象构造的时候,我们会先调用父类的构造方法,先构造父类对象再执行子类的构造方法:

那么为什么会出现这样情况呢?

子类对象中成员是有两部分组成的,父类继承下来的以及子类新增加的部分 。父子父子肯定是先有父再有子,那么在构造子类对象时候 ,先要调用父类的构造方法,将从父类继承下来的成员构造完整 ,然后再调用子类自己的构造方法,将子类自己新增加的成员初始化完整。

这里有个注意事项:

  1. 若父类显式定义无参或者默认的构造方法,在子类构造方法第一行默认有 隐含的super() 调用,即调用父类构造方法
  2. 如果父类构造方法是带有参数的,此时需要用户为子类显式定义构造方法,并在子类构造方法中选择合适的父类构造方法调用,否则编译失败

8. 代码块的执行顺序

代码块分为几个重要的代码块:实例代码块静态代码块, 那么在有继承关系的时候,这几个代码块的执行顺序是怎么样的呢?

通过运行结果我们就可以知道,代码块的执行顺序是:父类静态代码块 --> 子类静态代码块 --> 父类实例代码块 --> 父类构造方法 --> 子类实例代码块 --> 子类构造方法

注意:当第二次实例化子类对象时,父类和子类的静态代码块都将不会再执行:

9. protected访问修饰限定符

为了实现封装特性, Java 中引入了访问限定符,主要限定:类或者类中成员能否在类外或者其
他包中被访问。

  1. 被public修饰

此时的Dog类和Main类在不同的包底下并且不是继承关系,但是在Main类中任然能够访问Dog类中的成员变量 ,所以public的权限是最广的。

  1. 被protected修饰

此时的Dog类和Main类在不同的包底下是继承关系,在Main类中能够访问Dog类中的成员变量 ,那么这就是protected访问修饰符的权限(不同包有继承关系的类能够访问),如果不继承的话:

就会像上图中一样发生报错。这里有一个很重要的注意事项:

被protected修饰,可以访问不同包的有继承关系的类,但是访问的时候我们是需要通过new子类对象来进行访问的,直接new父类对象是访问不了的

10. 继承方式

在我们的Java中只支持单继承、多层继承、不同类继承同一个类,但是不支持多继承:

(1)单继承

这种一个类只继承另一个类的继承方式叫做单继承。

(2)多层继承

这种一个类继承另一个类,此时又有一个类继承该类的继承方式叫做多继承

(3)不同类继承同一个类

此时狗类和猫类都继承Animal这个类

注意:一个类是不能继承多个类的,也就是所谓的多继承~是不存在的

11.final关键字

一般我们不希望出现超过三层的继承关系, 如果继承层 次太多, 就需要考虑对代码进行重构了, 如果想从语法上进行限制继承, 就可以使用 final 关键字,final关键字有三种使用方式:可以修饰变量、可以修饰成员方法、可以修饰类。
(1)修饰变量

当我们用final修饰变量的时候,就具备了常量的属性,此时变量的值是不能进行修改的

(2)修饰成员方法

当我们的成员方法被final修饰,此时的成员方法是不能被重写的

(3)修饰类

当类被final修饰,说明当前类是不能被继承的

12. 继承与组合

组合和继承类似 , 组合也是一种表达类之间关系的方式 , 也是能够达到代码重用的效果。组合并没有涉及到特殊的语法(诸如 extends 这样的关键字 ), 仅仅是将一个类的实例作为另外一个类的字段。

继承表示对象之间是 is-a 的关系 ,比如:狗是动物,猫是动物.....
组合表示对象之间是 has-a 的关系 ,比如:水果篮中有苹果、香蕉.....
用代码实现一个组合:

那么此时这种表达类之间关系的方式就是一种组合~

结语

那么以上就是本期Java继承的全部内容啦~希望大家收获满满,在此感谢大家的观看!!!

相关推荐
S-X-S13 分钟前
算法总结-数组/字符串
java·数据结构·算法
linwq818 分钟前
设计模式学习(二)
java·学习·设计模式
※DX3906※31 分钟前
cpp实战项目—string类的模拟实现
开发语言·c++
wjs202439 分钟前
Nginx 安装配置指南
开发语言
桦说编程1 小时前
CompletableFuture 超时功能有大坑!使用不当直接生产事故!
java·性能优化·函数式编程·并发编程
@_@哆啦A梦1 小时前
Redis 基础命令
java·数据库·redis
美味小鱼1 小时前
实践Rust:编写一个猜数字游戏
开发语言·游戏·rust
Dr.勿忘2 小时前
C#面试常考随笔8:using关键字有哪些用法?
开发语言·unity·面试·c#·游戏引擎
字节全栈_rJF2 小时前
性能测试 —— Tomcat监控与调优:status页监控_tomcat 自带监控
java·tomcat
dal118网工任子仪2 小时前
92,[8] 攻防世界 web Web_php_wrong_nginx_config
开发语言·php