七、继承

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

继承的好处

  • 提高代码的复用性

  • 提高代码的扩展性

  • 类与类之间产生了关系,是学习多态的前提。例如:学生 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. 远程连接mysql出现1045错误的解决办法

    第一步:停止MySQL服务 第二步:在你MySQL的安装目录下找到my.ini,文件,打开文件查找到 [mysqld] ,在其下方添加上一行 skip-grant-tables,然后保存. 第三步:启 ...

  2. SpringBoot使用拦截器、过滤器、监听器

    目录 ## 过滤器 PS: 原文链接https://www.cnblogs.com/haixiang/p/12000685.html,转载请注明出处 过滤器简介 过滤器的使用 拦截器 拦截器介绍 使用 ...

  3. 寻找键盘bug

    被这句阻拦了

  4. Mac从拆箱到入门

    Mac从拆箱到入门   记录首次使用Mac的我的历程,不是专业的Mac使用教程,只是简单的记录.还有我在使用过程中一些用到的功能都一些小提示吧.  1.首次开机配置,对于一个完全的新手来说(也就是我) ...

  5. 转:轻松把玩HttpClient之封装HttpClient工具类(一)(现有网上分享中的最强大的工具类)

    搜了一下网络上别人封装的HttpClient,大部分特别简单,有一些看起来比较高级,但是用起来都不怎么好用.调用关系不清楚,结构有点混乱.所以也就萌生了自己封装HttpClient工具类的想法.要做就 ...

  6. FF.PyAdmin 接口服务/后台管理微框架 (Flask+LayUI)

    源码(有兴趣的朋友请Star一下) github: https://github.com/fufuok/FF.PyAdmin gitee: https://gitee.com/fufuok/FF.Py ...

  7. luogu P1358 扑克牌

    题目描述 组合数学是数学的重要组成部分,是一门研究离散对象的科学,它主要研究满足一定条件的组态(也称组合模型)的存在.计数以及构造等方面的问题.组合数学的主要内容有组合计数.组合设计.组合矩阵.组合优 ...

  8. Java修炼——对象数组存储表格数据

    数组存基本数据类型,也可以存引用数据类型 对象数组:使用数组存储对象(自定义对象) 先定义Person的三个私有变量,给他取值赋值方法,重写toString方法. package com.bjsxt. ...

  9. Docker学习-jenkins+github实现持续集成和部署

    上一篇介绍了docker环境搭建,本篇继续深入,结合jenkins利用docker-compose容器编排简单介绍下如何实现个人学习的持续集成/部署. 本篇学习曲线: 1.安装/运行jenkins容器 ...

  10. 使用iCamera 测试AR0331 300w高分辨率摄像头小结

    使用iCamera 测试AR0331 300w高分辨率摄像头小结 先看下sensor特性 分辨率最高可达:2048*1536=300w像素 1080p帧率最高可达60fps 本次使用usb2,帧率14 ...