七、继承

多个类中存在相同属性和行为时,将这些内容抽取到单独一个类中,那么多个类中无需再定义这些属性和行为,只需要和抽取出来的类构成继承关系。

继承的好处

  • 提高代码的复用性

  • 提高代码的扩展性

  • 类与类之间产生了关系,是学习多态的前提。例如:学生 is - a 人。

继承的格式(extends

【修饰符】 class 父类 {
  ...
}

【修饰符】 class 子类 extends 父类 {
  ...
}

继承的特点

1、Java只支持单继承,每一个子类只有一个直接父类

2、Java支持多层继承,父类还可以有父类

3、子类会继承父类所有特征,包括成员变量、成员方法,哪怕是私有的,私有的在子类中无法直接使用。

4、子类不会继承父类的代码块、构造器等。

5、但是子类一定会调用父类的实例初始化方法。

继承的特点一:成员变量

1、父类成员变量私有化(private)

  • 父类中的成员,无论是公有(public)还是私有(private),均会被子类继承

  • 子类虽会继承父类私有(private)的成员,但子类不能对继承的私有成员直接进行访问,可通过继承的get/set方法进行访问。如图所示:

子类创建对象时,在堆内存中是要为从父类继承的成员变量分配内存空间。

2、父类子类成员变量重名

我们说父类的所有成员变量都会继承到子类中,那么如果子类出现与父类同名的成员变量会怎么样呢?

结论:

(1)当父类的成员变量私有化时,在子类中是无法直接访问的,所以是否重名不影响,如果想要访问父类的私有成员变量,只能通过父类的get/set方法访问;

(2)当父类的成员变量非私有时,在子类中可以直接访问,所以如果有重名时,就需要加“super."进行区别。

格式:super.父类成员变量名,但是前提条件,这个成员变量没有私有化。

说明:虽然我们可以区分父子类的重名成员变量,但是实际开发中,我们不建议这么干。

继承的特点二:成员方法

我们说父类的所有方法子类都会继承,但是当某个方法被继承到子类之后,子类觉得父类原来的实现不适合于子类,该怎么办呢?

1、方法重写

1.@Override:写在方法上面,用来检测是不是有效的正确覆盖重写。这个注解就算不写,只要满足要求,也是正确的方法覆盖重写。建议保留

2.必须保证父子类之间方法的名称相同,参数列表也相同

3.子类方法的返回值类型必须【小于等于】父类方法的返回值类型(小于其实就是是它的子类,例如:Student < Person)。

注意:如果返回值类型是基本数据类型和void,那么必须是相同

4.子类方法的权限必须【大于等于】父类方法的权限修饰符。 小扩展提示:public > protected > 缺省 > private

5.几种特殊的方法不能被重写

  • 静态方法不能被重写

  • 私有等在子类中不可见的方法不能被重写

  • final方法不能被重写

小贴士:重写时,用到super.父类成员方法,表示调用父类的成员方法。

继承的特点三:构造方法

当类之间产生了关系,其中各类中的构造方法,又产生了哪些影响呢?

首先我们要回忆两个事情,构造方法的定义格式和作用。

  1. 构造方法的名字是与类名一致的。

    所以子类是无法继承父类构造方法的。

  2. 构造方法的作用是初始化实例变量的,而子类又会从父类继承所有成员变量

    所以子类的初始化过程中,必须先执行父类的初始化动作。子类的构造方法中默认有一个super() ,表示调用父类的实例初始化方法,父类成员变量初始化后,才可以给子类使用。

如果父类没有无参构造怎么办?

解决办法:在子类构造器中,用super(实参列表),显示调用父类的有参构造解决。

结论:

子类对象实例化过程中必须先完成从父类继承的成员变量的实例初始化,这个过程是通过调用父类的实例初始化方法来完成的。

  • super():表示调用父类的无参实例初始化方法,要求父类必须有无参构造,而且可以省略不写;

  • super(实参列表):表示调用父类的有参实例初始化方法,当父类没有无参构造时,子类的构造器首行必须写super(实参列表)来明确调用父类的哪个有参构造(其实是调用该构造器对应的实例初始方法)

  • super()和super(实参列表)都只能出现在子类构造器的首行

继承的特点四:单继承限制

1、Java只支持单继承,不支持多继承。

2、Java支持多层继承(继承体系)。

顶层父类是Object类。所有的类默认继承Object,作为父类。

3、子类和父类是一种相对的概念。

4、一个父类可以同时拥有多个子类

final关键字

final:最终的,不可更改的,它的用法有:

1、修饰类

表示这个类不能被继承,没有子类

2、修饰方法

表示这个方法不能被子类重写

3、声明常量

final修饰某个变量(成员变量或局部变量),表示它的值就不能被修改,即常量,常量名建议使用大写字母。

如果某个成员变量用final修饰后,没有set方法,并且必须初始化(可以显式赋值、或在初始化块赋值、实例变量还可以在构造器中赋值)

当修饰的是数组变量时,数组的地址值不可以改变但数组元素可以改变。

this关键字

this代表当前对象的引用(地址值),即对象自己的引用。

  • this可以用于非静态代码块和构造器中:表示正在创建的那个实例对象,即正在new谁,this就代表谁

  • this用于实例方法中:表示调用该方法的对象,即谁在调用,this就代表谁。

this使用格式

1、this.成员变量名

当方法的局部变量与当前对象的成员变量重名时,就可以在成员变量前面加this.,如果没有重名问题,就可以省略this.

2、this.成员方法

调用当前对象自己的成员方法时,都可以加"this.",也可以省略,实际开发中都省略

3、this()或this(实参列表)

当需要调用本类的其他构造器时,就可以使用该形式。

要求:

必须在构造器的首行

如果一个类中声明了n个构造器,则最多有 n - 1个构造器中使用了"this(【实参列表】)",否则会发生递归调用死循环

super关键字

super代表父类的引用

注意:在子类中通过super去引用父类的成员时,必须保证该成员在子类中是仍然可见的,即注意权限修饰符问题

(1)super.成员变量

在子类中访问父类的成员变量,特别是当子类的成员变量与父类的成员变量重名时。

(2)super.成员方法

在子类中调用父类的成员方法,特别是当子类重写了父类的成员方法时

(3)super()或super(实参列表)

在子类的构造器首行,用于表示调用父类的哪个构造器(本质上是该构造器对应的实例初始化方法)

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

this()和this(实参列表) 与 super()或super(实参列表) 不能同时出现

就近原则:解决复杂问题

  • 没有super和this

    • 在构造器、代码块、方法中如果出现使用某个变量,先查看是否是当前块声明的局部变量,

    • 如果不是局部变量,先从当前类去找成员变量

    • 如果当前类中没有找到,会往上找父类的(非private,跨包还不能是缺省的)

  • this :代表当前对象的引用

    • 通过this找成员变量和成员方法时,先从当前类中找,没有的会往上找父类的(非private,跨包还不能是缺省的)。

    • 但是this()或this(实参列表)只会在本类中找

  • super :代表父类的存储空间标识(可以理解为父类的引用)。

    • 通过super找成员变量和成员方法时,直接从父类空间(包含父类的父类继承的)找

    • super()或super(实参列表)只能从直接父类

    • 通过super只能访问父类在子类中可见的(非private,跨包还不能是缺省的)

  • 即:super一定是从直接父类开始找

    this一定是从当前类的成员开始找

    即没有this又没有super,一定是从局部变量开始找

注意:super和this都不能出现在静态方法和静态代码块中,因为super和this都是存在与对象中的

继承与初始化

类初始化

实际上,类初始化的过程时在调用一个<clinit>()方法,而这个方法是编译器自动生成的。编译器会将如下两部分的所有代码,按顺序合并到类初始化<clinit>()方法体中。

(1)静态类成员变量的显式赋值语句

(2)静态代码块中的语句

整个类初始化只会进行一次,如果子类初始化时,发现父类没有初始化,那么会先初始化父类。

结论:

每一个类都有一个类初始化方法<clinit>()方法,然后子类初始化时,如果发现父类没有加载和没有初始化,会先加载和初始化父类,然后再加载和初始化子类。一个类,只会初始化一次。

实例初始化

实际上我们编写的代码在编译时,会自动处理代码,整理出一个<clinit>()的类初始化方法,还会整理出一个或多个的<init>(...)实例初始化方法。一个类有几个实例初始化方法,由这个类有几个构造器决定。

实例初始化方法的方法体,由四部分构成:

(1)super()或super(实参列表) 这里选择哪个,看原来构造器首行是哪句,没写,默认就是super()

(2)非静态实例变量的显示赋值语句

(3)非静态代码块

(4)对应构造器中的代码

特别说明:其中(2)和(3)是按顺序合并的,(1)一定在最前面(4)一定在最后面

执行特点:

  • 创建对象时,才会执行,

  • 调用哪个构造器,就是指定它对应的实例初始化方法

  • 创建子类对象时,父类对应的实例初始化会被先执行(父类的clinit<>(有参或无参)方法执行完后再执行子类的init<>(有参或无参)方法),执行父类哪个实例初始化方法,看用super()还是super(实参列表)

结论:

类初始化肯定优先于实例初始化。

类初始化只做一次。

实例初始化是每次创建对象都要进行。

Java基础语法06-面向对象-继承的更多相关文章

  1. Java基础语法(9)-面向对象之类的成员

    title: Java基础语法(9)-面向对象之类的成员 blog: CSDN data: Java学习路线及视频 1.面向对象特征--封装 为什么需要封装?封装的作用和含义? 我要用洗衣机,只需要按 ...

  2. Java基础语法(10)-面向对象之三大特征

    title: Java基础语法(9)-面向对象之类的成员 blog: CSDN data: Java学习路线及视频 1.面向对象特征--封装 为什么需要封装?封装的作用和含义? 我要用洗衣机,只需要按 ...

  3. 056 01 Android 零基础入门 01 Java基础语法 06 Java一维数组 03 一维数组的应用

    056 01 Android 零基础入门 01 Java基础语法 06 Java一维数组 03 一维数组的应用 本文知识点:数组的实际应用 程序开发中如何应用数组? 程序代码及其运行结果: 不同数据类 ...

  4. 055 01 Android 零基础入门 01 Java基础语法 06 Java一维数组 02 数组的概念

    055 01 Android 零基础入门 01 Java基础语法 06 Java一维数组 02 数组的概念 本文知识点:数组的概念 数组的声明创建.初始化 在学习数组的声明创建.初始化前,我们可以和之 ...

  5. Java基础语法(11)-面向对象之关键字

    title: Java基础语法(11)-面向对象之关键字 blog: CSDN data: Java学习路线及视频 1.this this是什么 它在方法内部使用,即这个方法所属对象的引用: clas ...

  6. 061 01 Android 零基础入门 01 Java基础语法 06 Java一维数组 08 一维数组总结

    061 01 Android 零基础入门 01 Java基础语法 06 Java一维数组 08 一维数组总结 本文知识点:一维数组总结 总结 注意点

  7. 060 01 Android 零基础入门 01 Java基础语法 06 Java一维数组 07 冒泡排序

    060 01 Android 零基础入门 01 Java基础语法 06 Java一维数组 07 冒泡排序 本文知识点:冒泡排序 冒泡排序 实际案例分析冒泡排序流程 第1轮比较: 第1轮比较的结果:把最 ...

  8. 059 01 Android 零基础入门 01 Java基础语法 06 Java一维数组 06 增强型for循环

    059 01 Android 零基础入门 01 Java基础语法 06 Java一维数组 06 增强型for循环 本文知识点:增强型for循环 增强型for循环格式 案例练习增强型for循环 数组名字 ...

  9. 058 01 Android 零基础入门 01 Java基础语法 06 Java一维数组 05 案例:求数组元素的最大值

    058 01 Android 零基础入门 01 Java基础语法 06 Java一维数组 05 案例:求数组元素的最大值 本文知识点:求数组元素的最大值 案例:求数组元素的最大值 程序代码及其执行过程 ...

  10. 057 01 Android 零基础入门 01 Java基础语法 06 Java一维数组 04 案例:求整型数组的数组元素的元素值累加和

    057 01 Android 零基础入门 01 Java基础语法 06 Java一维数组 04 案例:求整型数组的数组元素的元素值累加和 本文知识点:求整型数组的数组元素的元素值累加和 案例:求整型数 ...

随机推荐

  1. postgresql密码加强-passwordcheck源码修改三种以上字符

    目录 1.使用方式 2.效果 3.源码修改 1.参考pg_cron的源码在配置文件内增加一个参数 2.修改源码配置校验数字 因数据库入网检测须修改密码级别,在源有的passwordcheck插件上进行 ...

  2. html代码/如何做到有横线无竖线的表格/或横线有颜色/竖线没颜色

    改变它的css样式,table{ border-collapse:collapse;}table tr td{ border-bottom:1px solid #dedede;}

  3. mysql-常用组件之触发器

    基本概念 触发器是一种特殊的存储过程,不像存储过程需要显示调用,触发器通过监控表事件(增删改操作)自动触发某条 sql 的执行,可以用于购物车加购后库存减少等场景. 触发器基本操作 1. 创建触发器 ...

  4. Preact(React)核心原理详解

    原创: 宝丁 玄说前端 本文作者:字节跳动 - 宝丁 一.Preact 是什么 二.Preact 和 React 的区别有哪些? 三.Preact 是怎么工作的 四.结合实际组件了解整体渲染流程 五. ...

  5. MyBatis更新,删除,插入

    UserMapper.java: package com.bjsxt.mapper; import java.util.List; import org.apache.ibatis.annotatio ...

  6. python实现十大核心算法(桶排没实例)

    # author:sevenduke # 2019-06-11 # 一.交换排序 # 排序算法的温故:冒泡排序 def dubblesort(arr): for i in range(0, len(a ...

  7. [TimLinux] JavaScript BOM浏览器对象模型

    1. 简介 ECMAScript是JavaScript的核心,但是如果要在WEB中使用JavaScript,那么BOM则无疑才是真的的核心.BOM提供了很多对象,用于访问浏览器的功能,这些功能与任何网 ...

  8. cesium 结合 geoserver 实现地图属性查询(附源码下载)

    前言 cesium 官网的api文档介绍地址cesium官网api,里面详细的介绍 cesium 各个类的介绍,还有就是在线例子:cesium 官网在线例子,这个也是学习 cesium 的好素材. 内 ...

  9. TypeScript - 泛型

    什么是泛型 官方是这样介绍的: 软件工程中,我们不仅要创建一致的定义良好的API,同时也要考虑可重用性. 组件不仅能够支持当前的数据类型,同时也能支持未来的数据类型,这在创建大型系统时为你提供了十分灵 ...

  10. flex布局中flex-grow与flex-shrink的计算方式

    CSS 中的 Flex(弹性布局) 可以很灵活的控制网页的布局,其中决定 Flex 布局内项目宽度/高度的是三个属性: flex-basis, flex-grow, flex-shrink. flex ...