1. 继承的概述
  2. 继承的特点
  3. super 关键字
  4. 函数覆盖
  5. 子类的实例化过程
  6. final 关键字

1. 继承的概述

继承是类与类之间的关系.

继承的好处:

  • 提高了代码的复用性
  • 让类与类之间产生了关系, 给第三个特征多态提供了前提

继承按直接父类的个数分为两种:

  1. 单继承: 一个子类只能有一个直接父类
  2. 多继承: 一个子类可以有多个直接父类, 此继承方式在 java 中不允许.

    java 对此种继承方式进行了改良, 即通过"多实现"的方式来实现的.
// 不直接支持多继承的原因: 多个父类中有相同成员, 会产生调用的不确定性
class A
{
void show()
{
System.out.println("a");
}
} class B
{
void show()
{
System.out.println("b");
}
} class C extends A,B
{ } new C().show(); // 由于 C 继承了 A 和 B, 此时,出现调用的不确定性

继承体系

  • java 支持多重继承, 即 C 继承 B, B 继承 A.

当要使用一个继承体系时
  1. 查看该体系中的顶层类(如上图中的 A 类), 了解该体系的基本功能
  2. 创建体系中的最子类对象(如上图中的 D 类), 完成功能的使用

什么时候定义继承呢?

  • 当类与类之间存在着所属关系时, 就定义继承.
  • 所属关系: is a 关系

    例如:狗类是犬科类的一种,狗类就可以继承犬科类.

2. 继承的特点

在子父类中,成员的特点体现

  1. 成员变量
  2. 成员函数
  3. 构造函数

成员变量

  • 当本类的成员变量和局部变量同名用 this 区分;

    当子父类中的成员变量同名用 super 区分.
  • this 和 super 的用法很相似.不同之处在于
    • this: 代表一个本类对象的引用
    • super: 代表一个父类的空间, 不代表父类对象
  • 子类不能直接访问父类中私有内容, 但是可以通过 get 方法间接访问父类中私有内容
class Fu
{
int num = 4;
} class Zi extends Fu
{
int num = 5; void show()
{
System.out.println(this.num+"..."+super.num);
}
} class ExtendsDemo
{
public static void main(String[] args)
{
Zi z = new Zi();
z.show();
}
}

// 示例: 写出程序结果
class Super
{
int i = 0;
public Super(String a) // 带参数构造函数
{
System.out.println("A");
i = 1;
}
public Super() // 空参数构造函数
{
System.out.println("B");
i += 2;
}
} class Demo extends Super
{
public Demo(String s) // 带参数构造函数
{
System.out.println("C");
i += 5; // 子类中没有定义 i, 直接访问父类的 i
}
public static void main(String[] args)
{
int i = 4;
Super d = new Demo("A");
System.out.println(d.i);
}
}
// 输出结果: B C 7

成员函数

当子父类中出现成员函数一模一样的情况, 会运行子类的函数, 这种现象称为覆盖操作. 这是函数在子父类中的特性.

覆盖操作注意事项:

  1. 子类方法覆盖父类方法时, 子类成员函数权限必须要大于等于父类成员函数时的权限.

    权限分为三种: public, private 和 默认权限.
  2. 静态只能覆盖静态, 或被静态覆盖
  3. 必须保证子类和父类函数一模一样, 即 返回值类型相同, 函数名一样, 参数列表一样.
// 示例1: 写出程序结果
class Super
{
public int get(){return 4;}
}
class Demo extends Super
{
public long get() {return 5;} // 编译失败, 函数调用的不确定性
public static void main(String[] args)
{
Super s = new Demo();
System.out.println(s.get());
}
} // 示例2: 写出错误答案错误的原因, 用单行注释的方式
class Demo
{
int show(int a, int b){return 0;}
}
下面哪些函数可以存在于 Demo 的子类中
A. public int show(int a, int b){return 0;} // 可以, 函数覆盖
B. private int show(int a, int b){return 0;} // 不可以, 权限不够
C. private int show(int a, long b){return 0;} // 可以, 子类特有方法
D. public short show(int a, int b){return 0;} // 不可以, 调用的不确定性
E. static int show(int a, int b){return 0;} // 不可以, 静态只能覆盖静态

函数的两个特性:

  1. 重载: 发生在同一个子类中
  2. 覆盖: 也称为重写(覆写), override

什么时候使用覆盖操作?

当对一个类进行子类的扩展时, 子类需要保留父类的功能声明,

但是要定义子类中该功能的特有内容时, 就使用覆盖操作完成.

// 早期手机来电显示, 只能显示电话号码
class ExtendsDemo
{
public static void main(String[] args)
{
Phone p = new Phone();
p.show
}
} class Phone
{
void show()
{
System.out.println("number"); //来电显示电话号码
}
} // 手机升级, 增加来电显示姓名, 大头贴和电话号码
// 此时,相当于代码升级,不应该在源代码上过分修改. class NewPhone extends Phone // 继承父类
{
void show() // 函数覆盖
{
System.out.println("name"); // 增加姓名
System.out.println("pic"); // 增加大头贴
// System.out.println(number);
super.show(); // 调用父类 show() 方法
}
}

构造函数

class Fu
{
Fu() //父类构造函数
{
System.out.println("fu run");
}
} class Zi extends Fu
{
Zi() // 子类构造函数
{
System.out.println("zi run");
}
} class ExtendsDemo
{
public static void main(String[] args)
{
new Zi();
}
}

运行结果:

在子类构造对象时, 发现访问子类构造函数时, 父类的构造函数也运行了.

为什么呢?

原因是: 在子类的构造函数中第一行有一个默认的隐式语句, super(); 调用的就是父类中的空参数的构造函数.

如果父类中的构造函数有参数, 需要使用 super 指定.

为什么子类实例化的时候要访问父类中的构造函数呢?

因为子类继承了父类, 获取到了父类中的内容(属性), 所以在使用父类内容之前,要先看父类是如何对自己

的内容进行初始化的.所以子类在构造对象时, 必须访问父类中的构造函数.为类完成这个必须的动作, 就在

子类的构造函数中加入了 super() 语句.

如果父类中没有定义空参数构造函数, 那么子类的构造函数必须用 super 明确要调用父类中哪个构造函数.

同时, 子类的构造函数中如果使用 this 调用类本类构造函数时,那么 super 就没有了, 因为 super 和

this 都只能定义在第一行, 所以只能有一个. 但是可以保证的是, 子类中肯定会有其他的构造函数访问父类

的构造函数.

注意: super 语句必须定义在子类构造函数的第一行, 因为父类的初始化动作要先完成.

// 子类实例化过程: 子类中所有的构造函数默认都会访问父类中的空参数的构造函数
class Fu
{
Fu()
{
System.out.println("A");
} Fu(int x)
{
System.out.println("B"+ x);
}
} class Zi extends Fu
{
Zi()
{
System.out.println("C");
} Zi(int x)
{
System.out.println("D"+ x)
}
} class ExtendsDemo
{
public static void main(String[] args)
{
new Zi(6);
}
} // 输出结果: A D6
// 子类初始化,必须先访问父类的构造函数
class Fu
{
Fu()
{
System.out.println("A");
} Fu(int x)
{
System.out.println("B"+ x);
}
} class Zi extends Fu
{
Zi()
{
super(); // 通过这个构造函数,默认的隐式语句 super(); 访问父类中的空参数构造函数
System.out.println("C");
} Zi(int x)
{
this(); // 访问本类中其他构造函数
System.out.println("D"+ x)
}
} class ExtendsDemo
{
public static void main(String[] args)
{
new Zi(6);
}
}

4. 子类的对象实例化过程

class Fu
{
Fu() // 构造函数
{
super(); // 默认隐式语句
show();
return;
} void show()
{
System.out.println("fu show");
}
} class Zi extends Fu
{
int num = 8; Zi() // 默认构造函数
{
super();
return;
} void show()
{
System.out.println("zi show..."+num);
}
} class ExtendsDemo
{
public static void main(String[] args)
{
Zi z = new Zi();
}
} // 运行结果: zi show...0

一个对象实例化过程

以 Person p = new Person(); 为例:

  1. JVM 会读取指定的路径下的 Person.class 文件, 并加载进内存,

    并会先加载 Person 的父类(如果有直接的父类的情况下)
  2. 在堆内存中, 开辟空间, 分配内存地址
  3. 在对象空间中, 对对象中的属性进行默认初始化
  4. 调用对应的构造函数进行初始化
  5. 在构造函数中, 第一行会先调用父类中的构造函数进行初始化
  6. 父类初始化完毕后, 在对子类的属性进行显示初始化
  7. 再进行子类构造函数的特定初始化
  8. 初始化完毕后, 将地址值赋给引用变量

5. final 关键字

  1. final 是一个修饰符, 可以修饰类, 方法, 变量
  2. final 修饰的类不可以被继承
  3. final 修饰的方法不可以被覆盖
  4. final 修饰的变量是一个常量, 只能赋值一次
  5. 写法规范: 常量所有单词都大写, 若有多个单词, 使用下划线(_)连接
  6. 内部类只能访问被 final 修饰的局部变量







    参考资料

Java 之继承和 final 关键字的更多相关文章

  1. Java的继承,final关键字,super关键字

    1.继承的初始化顺序: 父类—>父类的初始化对象中的属性—>父类的构造方法—>子类—>子类的初始化对象中的属性—>子类的构造方法 若有构造方法:则先执行属性,再执行构造方 ...

  2. “全栈2019”Java第五十一章:继承与final关键字详解

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第 ...

  3. 《JAVA学习笔记 (final关键字)》

    [14-9]面向对象-final关键字 /* 继承的弊端,打破封装性. 不让其他类继承该类,就不会有重写. 怎么能实现呢?通过Java中的一个关键子来实现,final(最终化). [final关键字] ...

  4. Java的static和final关键字的用法

    static关键字的用法 static的意思是"'静态的",在java里面可用于修饰属性和方法. static关键字的应用应注意以下几种情形: 1.static作用于某个字段,一个 ...

  5. 2017.10.23 Java 面向对象深入学习---final 关键字、static关键字、匿名对象等

    今日内容介绍 1.final 关键字 2.static 关键字 3.匿名对象 4.内部类 5.包的声明与访问 6.访问修饰符 7.代码块 第一节课 01(面向对象)final关键字概念.avi 02: ...

  6. 深入java面向对象二:final关键字

    文章内容源于对<疯狂java讲义>及<疯狂Java:突破程序员基本功的16课>学习和总结. 一. final成员变量 final 修饰变量时,表示该变量一旦获取了值就不可以改变 ...

  7. java学习面向对象之final关键字

    之前我们讲过继承的相关知识了,继承就是子类继承父类的属性和方法并且还可以覆盖父类的方法.但是这样有一个缺陷是什么呢,就是当我们一个类当中涉及一些封装的核心的东西或者对整个系统非常关键的方法或者类的时候 ...

  8. (五)《Java编程思想》——final关键字

    可能使用final的三种情况:数据.方法.类. 1.final数据 final 常量必须是基本类型数据,且在定义时须赋值: 一个既是static又是final的域只占据一段不能改变的存储空间,只有一份 ...

  9. 安卓开发(Java)中关于final关键字与线程安全性

    前言 学习新知识固然重要,但是时常往回看看,温故知新是很必要的.回顾一下线程安全性和final关键字. 正文 从Java 5开始,final keyword一个特殊用法是在并发库中一个非常重要且经常被 ...

随机推荐

  1. google_gflags使用

    gflags是google开源的一个解析命令行参数的工具. 最简单的demo #include <iostream> #include <gflags/gflags.h> us ...

  2. PHP中的正则表达式及模式匹配

    PHP中的正则表达式及模式匹配 PHP中对于正则处理文本提供了两种方式,一种是PCRE方式(PCRE库是一个实现了与perl 5在语法和语义上略有差异(详见下文)的正则表达式模式匹配功能的函数集. 当 ...

  3. lua 打印 table 拷贝table

    -- 打印table function print_lua_table (lua_table, indent) if lua_table == nil or type(lua_table) ~= &q ...

  4. binutils工具集之---objdump

    在嵌入式软件开发中,有时需要知道所生成的程序文件中的段信息以分析问题,或者需要查看c语言对应的汇编代码,此时,objdump工具就可以帮大忙了.obj——object  dump:转储. #inclu ...

  5. RTT第一个工程

    第一个RTT工程 1. 配置工程 选择芯片STM32F103C8(其包含该芯片的Flash及SRAM介绍): Jlink  SW模式 output->Debug info/Browse info ...

  6. windows config yii framework

    download and config download yii-1.1.12 unzip into yii-1.1.12 config yii-1.1.12 dir an apache httpdo ...

  7. shell30题之第一题

    1.1.1 Shell面试题1:批量生成随机字符文件名案例 使用for循环在/oldboy目录下批量创建10个html文件,其中每个文件需要包含10个随机小写字母加固定字符串oldboy,名称示例如下 ...

  8. 自己编写Android Studio插件 别停留在用的程度了(转载)

    转自:自己编写Android Studio插件 别停留在用的程度了 1概述 相信大家在使用Android Studio的时候,或多或少的会使用一些插件,适当的配合插件可以帮助我们提升一定的开发效率,更 ...

  9. 第二百二十七节,jQuery EasyUI,ComboTree(树型下拉框)组件

    jQuery EasyUI,ComboTree(树型下拉框)组件 学习要点: 1.加载方式 2.属性列表 3.方法列表 本节课重点了解EasyUI中ComboTree(树型下拉框)组件的使用方法,这个 ...

  10. 微信公众号实现zaabix报警2017脚本(升级企业微信后)

    #!/bin/bash CropID='xxxxxxxxxxxxxxxxx' Secret='xxxxxxxxxxxxxxxx' GURL="https://qyapi.weixin.qq. ...