Java 面向对象高级 继承
1. 继承
1.1 面向对象的三大特征
- 封装
把离散的数据/行为封装成一个整体 - 继承
- 多态
1.2 什么是继承/继承有什么好处
- 继承是类和类之间的父子关系, Java中提供关键字
extends, 用于建立类与类之间的关系
eg:
定义了一个Student类, 继承Person类
public class Student entends Person{
子类 父类
/派生类 /基类/超类
}
- 好处:
- 可以把多个子类中的重复代码抽取到父类中, 提高代码复用性
- 子类可以在父类的基础上, 增加其他功能, 使子类强大
eg:
Person.java
package oopextends.text1;
public class Person {
String name;
int age;
public void eat(){
System.out.println("吃饭");
}
}
Student.java
package oopextends.text1;
public class Student extends Person{
//子类特有的内容
//特有属性
String grade;
public void study(){
System.out.println("学生在学习");
}
}
Teacher.java
package oopextends.text1;
public class Teacher extends Person{
//子类特有的内容
//特有属性
String subject;
public void teach(){
System.out.println("老师在教书");
}
}
Text.java
package oopextends.text1;
public class Text {
static void main() {
Student s = new Student();
s.name = "张三";
s.age = 18;
s.grade = "高三";
s.study();
s.eat();
Teacher t = new Teacher();
t.name = "李四";
t.age = 35;
t.subject = "数学";
t.teach();
t.eat();
}
}
1.3 如何设计继承结构
- 当类与类之间, 存在形同(共性)的内容, 并满足子类是父类的一种, 就可以考虑使用继承, 来优化代码
- 父类起名要能代表所有的子类
eg:
现在有三个电子设备, 请设计他们的继承结构
- 安卓手机:
- 属性: 品牌, 价格
- 行为: 打电话, 发短信, nfc功能
- 苹果手机:
- 属性: 品牌, 价格
- 行为: 打电话, 发短信
- 笔记本电脑
- 属性: 品牌, 价格
- 行为: 编程
设计继承结构:
画图, 从下到上 -> 分类 -> 抽取共性的内容不断往上抽取(从下往上抽) -> 写代码(从下往上写)![![[Pasted image 20260419213044.png|600]]](https://i-blog.csdnimg.cn/direct/c8dcc330b8b74d5abd99f6d5c36fd68b.png)
1.4 继承的特点
-
IDEA中子类特有的是黑色加粗, 没有加粗的是父类的
![![[Pasted image 20260419210305.png|500]]](https://i-blog.csdnimg.cn/direct/f5e1e8b4fa5f405b903700a09a46bc29.png)
-
Java只支持单继承, 不支持多继承, 但支持多层继承
- 支持单继承: 一个子类只能继承一个父类
- 不能多继承: 子类不能继承多个父亲
- 多层继承:
- 直接父类与间接父类(没有爷类的概念)
- 顶级父类
Object(没有父类的父类默认为Object)
1.5 继承中成员的特点
1.5.1 成员变量的特点
-
书写规则: 把多个子类中相同的属性抽取父亲当中(抽取共性)
-
调用规则: 遵守就近原则
-
就近原则: 谁离我近, 我就用谁
-
eg:
![![[Pasted image 20260419215841.png|550]]](https://i-blog.csdnimg.cn/direct/b8bb7ea89ae540eaa8f70b2701b981f4.png)
![![[Pasted image 20260419220502.png|600]]](https://i-blog.csdnimg.cn/direct/2a34ab4477de41b4b10effdaee9c41f7.png)
注意: 最多到父类, 父类的父类就无法获取了
注意: 本类没有也最高只能到第一个父类![![[Pasted image 20260419221133.png]]](https://i-blog.csdnimg.cn/direct/2097e6061b7541ee8670bfe8797d2e25.png)
-
1.5.2 成员方法的特点
-
书写规则: 把多个子类中共性的成员方法抽取到父类中(抽取共性)
-
调用规则: 遵守就近原则
![![[Pasted image 20260420150359.png|500]]](https://i-blog.csdnimg.cn/direct/5f9f04e6021c41fc8951b49b67d483c1.png)
-
方法的重写: 在子类中, 把父类的方法再写一遍, 方法申明保持一致(方法的修饰符, 名字, 小括号内的参数列表 )
-
使用场景: 如果父类的方法不能满足子类的要求了, 子类可以把方法再重写一边
-
小技巧: Alt+Ins / Alt + Fn + Del 选择重写方法, 可自动生成重写方法, 或者直接输入想要重写的方法的名称,回车
![![[Pasted image 20260420154710.png|150]]](https://i-blog.csdnimg.cn/direct/36ed03656dad498db884c9ca7712cd12.png)
-
注意:
- 如果父类里面的代码,我一行都不想用,此时把子类中的方法体重新完整写一遍即可(练习一)
- 如果父类里面的代码我还想用,此时我只是在父类的基础上再加其他的逻辑此时可以先通过super关键字调用父类的方法得到一个结果,再对这个结果进行操作即可(练习二)
-
![![[Pasted image 20260420153105.png]]](https://i-blog.csdnimg.cn/direct/047214157a034364a4624057d58fa39b.png)
package oopextends.text3;
public class FirstGenerationPhone {
public void call(){
System.out.println("打电话");
}
}
package oopextends.text3;
public class SecondGenerationPhone extends FirstGenerationPhone{
public void sendMessage(){
System.out.println("发短信");
}
}
package oopextends.text3;
public class ThirdGenerationPhone extends SecondGenerationPhone{
//注释: 给程序员看的
//注解: 给虚拟机看的
@Override//注解
public void call() {
System.out.println("视频通话");
}
public void playGame(){
System.out.println("玩游戏");
}
}
package oopextends.text3;
public class Text {
static void main() {
FirstGenerationPhone phone1 = new FirstGenerationPhone();
phone1.call();
SecondGenerationPhone phone2 = new SecondGenerationPhone();
phone2.call();
phone2.sendMessage();
ThirdGenerationPhone phone3 = new ThirdGenerationPhone();
phone3.call();
phone3.sendMessage();
phone3.playGame();
}
}
![![[Pasted image 20260420160442.png|500]]](https://i-blog.csdnimg.cn/direct/8988deff70ba451c99ad8249275c8ce8.png)
package oopextends.text4;
public class SmartDevice {
//属性
String name;
double price;
//行为
public double payment(){
if(price >= 0 && price <= 1000){
return price ;
}else if(price > 1000 && price <= 5000){
return price * 0.9;
}else if(price > 5000 && price <= 10000){
return price * 0.8;
}else if(price > 10000){
return price * 0.7;
}else{
return 0;
}
}
}
package oopextends.text4;
public class Phone extends SmartDevice{
@Override
public double payment() {
return super.payment()*0.9;
}
}
package oopextends.text4;
public class Laptop extends SmartDevice{
}
package oopextends.text4;
public class Pad extends SmartDevice {
}
package oopextends.text4;
public class Text {
static void main() {
Phone p = new Phone();
p.name = "iphone";
p.price = 6000;
System.out.println(p.payment());
Laptop l = new Laptop();
l.name = "lenovo";
l.price = 8000;
System.out.println(l.payment());
}
}
-
方法重写的注意事项和要求:
- 重写方法的名称、形参列表必须与父类中的一致,方法体按照实际需求书写
了解: 子类重写父类方法时,访问权限子类必须大于等于父类(空着不写<protected<public)了解: 子类重写父类方法时,返回值类型子类必须小于等于父类- 建议: 重写方法的申明和父类保持一致
- final修饰类为最终类, 里面所有的方法不能被重写
- private私有方法, static静态方法, final最终方法不能被重写
-
成员方法特点总结
- 继承中成员方法的特点:
- 书写规则: 抽取子类中的共性行为
- 调用规则: 就近原则
- this调用: 先访问本类, 再访问父亲
- super调用: 直接访问父亲
- 什么时方法重写?
- 在继承体系中, 子类出现了和父亲中一模一样的方法声明, 我们就称这个子类的这个方法是重写的方法
- 重写的方法要加上==
@Override注解==, 校验重写的语法是否正确
- 什么时候用方法重写?
当父类中的方法不能满足子类的要求, 需要进行方法的重写 - 重写方法有那些基本要求?
- 子类重写的方法申明跟父类保持一致
- private私有方法, static静态方法, final最终方法不能被重写
1.5.3 构造方法的特点
- 父类中的构造方法不会被子类继承, 只能通过super关键字调用
理解: 构造方法的方法名要与类名一致, 继承父类的名字就不一致了, 所以不能继承
![![[Pasted image 20260421185905.png]]](https://i-blog.csdnimg.cn/direct/b683f7ed72294949a6abc0dfd80ca6b6.png)
小细节
- 如果子类的构造方法未写super, JVM会加一个默认的super(), 先访问父类的无参构造
- 要访问父类带参构造, super(参数)必须写上, 不能省略
- 在创建对象的时候, 先执行父类的构造方法, 再执行子类的构造方法
- 低版本super(参数)必须写在带参构造方法的第一行, 但新版本(jdk25)不用
tips
- Alt+Ins / Alt + Fn + Del 用前面的方法也可以
package oopextends.text5;
public class Person {
//属性
String name;
int age;
//构造方法
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
}
package oopextends.text5;
public class Student extends Person{
//属性
String grade;
//构造方法
public Student() {
}
public Student(String name, int age, String grade) {
super(name, age);
this.grade = grade;
}
}
package oopextends.text5;
public class Teacher extends Person{
//属性
String subject;
//构造方法
public Teacher() {
}
public Teacher(String name, int age, String subject) {
super(name, age);
this.subject = subject;
}
}
package oopextends.text5;
public class Text {
static void main() {
Student s = new Student("张三", 23, "高三");
System.out.println(s.name + " " + s.age + " " + s.grade);
}
}
1.6 this关键字和super关键字
-
this内存角度: 表示当前方法的调用者的地址值
-
this代码角度: 利用this可以直接调用本类的成员(比如: 成员变量, 成员方法, 构造方法等)
-
super关键字: 代表使用父类中的内容
![![[Pasted image 20260421211525.png]]](https://i-blog.csdnimg.cn/direct/01e3229f14894bea91e133be98b311f2.png)
-
this(…) 访问本类的构造方法
细节:
若子类中有多个构造方法, 不能用this()互相调用, 一定要预留一个调用父类的构造方法
若构造方法中写上了this(), 就不能再写super()了, JVM也不会自动添加super()
![![[Pasted image 20260421220040.png]]](https://i-blog.csdnimg.cn/direct/5fa2d136ff8d46a18e6b6a45a0c92c83.png)
1.7 继承综合练习
1.7.1 学生老师
![![[Pasted image 20260422172121.png]]](https://i-blog.csdnimg.cn/direct/e74b95e19fe54e9da8301df8a1f3663c.png)
继承结构设计图:
![![[Excalidraw/Drawing 2026-04-22 17.27.20.excalidraw|600]]](https://i-blog.csdnimg.cn/direct/fd2ba93be35d4a85afb605becc17335a.png)
package oopextends.text7;
public class Person {
//属性
private String name;
private int age;
//构造方法
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
//get/set
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
//行为
public void eat(){
System.out.println(name+"在吃饭");
}
public void sleep(){
System.out.println(name+"在睡觉");
}
}
package oopextends.text7;
public class Student extends Person{
//属性
private String grade;
//构造方法
public Student() {
}
public Student(String name, int age, String grade) {
super(name, age);
this.grade = grade;
}
//get/set
public String getGrade() {
return grade;
}
public void setGrade(String grade) {
this.grade = grade;
}
//行为
public void study(){
System.out.println("学生正在学习");
}
}
package oopextends.text7;
public class Teacher extends Person{
//属性
private String subject;
//构造方法
public Teacher() {
}
public Teacher(String name, int age, String subject) {
super(name, age);
this.subject = subject;
}
//get/set
public String getSubject() {
return subject;
}
public void setSubject(String subject) {
this.subject = subject;
}
//行为
public void teach(){
System.out.println("老师正在教书");
}
}
package oopextends.text7;
public class BeachelorStudent extends Student{
//没有独有属性
//构造方法
public BeachelorStudent() {
}
public BeachelorStudent(String name, int age, String grade) {
super(name, age, grade);
}
//get/set 无属性, 不用写
//重写学习方法
@Override
public void study() {
System.out.println("本科同学正在攻读学士学位");
}
}
package oopextends.text7;
public class MasterStudent extends Student{
//没有独有属性
//构造方法
public MasterStudent() {
}
public MasterStudent(String name, int age, String grade) {
super(name, age, grade);
}
//重写学习方法
@Override
public void study() {
System.out.println("硕士研究生同学正在攻读硕士学位");
}
//重写睡觉方法
@Override
public void sleep() {
System.out.println("硕士研究生住宿条件升级, 在豪华版学生公寓睡觉");
}
}
package oopextends.text7;
public class MajorTeacher extends Teacher{
//没有独有属性
//构造方法
public MajorTeacher() {
}
public MajorTeacher(String name, int age, String grade) {
super(name, age, grade);
}
//重写学习方法
@Override
public void teach() {
System.out.println("专业教师正在教授专业知识");
}
}
package oopextends.text7;
public class GeneralTeacher extends Teacher{
//没有独有属性
//构造方法
public GeneralTeacher() {
}
public GeneralTeacher(String name, int age, String grade) {
super(name, age, grade);
}
//重写学习方法
@Override
public void teach() {
System.out.println("通识课老师正在教授通识知识");
}
}
package oopextends.text7;
public class Text {
static void main() {
BeachelorStudent bs = new BeachelorStudent("张三", 18, "大一");
System.out.println(bs.getName()+","+bs.getGrade()+","+bs.getAge());
bs.study();
bs.sleep();
bs.eat();
MasterStudent ms = new MasterStudent("李四", 20, "硕士");
System.out.println(ms.getName()+","+ms.getGrade()+","+ms.getAge());
ms.study();
ms.sleep();
ms.eat();
MajorTeacher mt = new MajorTeacher("王五", 35, "教授");
System.out.println(mt.getName()+","+mt.getSubject()+","+mt.getAge());
mt.teach();
mt.sleep();
mt.eat();
GeneralTeacher gt = new GeneralTeacher("赵六", 40, "副教授");
System.out.println(gt.getName()+","+gt.getSubject()+","+gt.getAge());
gt.teach();
gt.sleep();
gt.eat();
}
}
1.7.2 黑马员工
![![[Pasted image 20260422201825.png]]](https://i-blog.csdnimg.cn/direct/b375bb6b77fb4060807579702f870390.png)
继承结构设计图:![![[Excalidraw/Drawing 2026-04-22 20.19.06.excalidraw|600]]](https://i-blog.csdnimg.cn/direct/4d5a8b7a7e77402c9b572a73abf71f03.png)
package oopextends.text8;
public class Employee {
//属性
private int id;
private String name;
private String job;
//构造方法
public Employee() {
}
public Employee(int id, String name, String job) {
this.id = id;
this.name = name;
this.job = job;
}
//set/get
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getJob() {
return job;
}
public void setJob(String job) {
this.job = job;
}
//行为
public void work() {
System.out.println("员工正在工作");
}
}
package oopextends.text8;
public class Teacher extends Employee{
//无特有属性
//构造方法
public Teacher() {
}
public Teacher(int id, String name, String job) {
super(id, name, job);
}
//无set/get
//无特殊行为
}
package oopextends.text8;
public class AdminStaff extends Employee{
//无特有属性
//构造方法
public AdminStaff() {
}
public AdminStaff(int id, String name, String job) {
super(id, name, job);
}
//无set/get
//无特殊行为
}
package oopextends.text8;
public class Lecturer extends Teacher{
//无特有属性
//构造方法
public Lecturer() {
}
public Lecturer(int id, String name, String job) {
super(id, name, job);
}
//无set/get
//重写工作
@Override
public void work() {
System.out.println("讲师正在授课");
}
}
package oopextends.text8;
public class Maintainer extends AdminStaff{
//无特有属性
//构造方法
public Maintainer() {
}
public Maintainer(int id, String name, String job) {
super(id, name, job);
}
//无set/get
//重写工作
@Override
public void work() {
System.out.println("维护人员正在维护");
}
}
package oopextends.text8;
public class Buyer extends AdminStaff{
//无特有属性
//构造方法
public Buyer() {
}
public Buyer(int id, String name, String job) {
super(id, name, job);
}
//无set/get
//重写工作
@Override
public void work() {
System.out.println("采购人员正在采购");
}
}
package oopextends.text8;
public class Tutor extends Teacher{
//无特有属性
//构造方法
public Tutor() {
}
public Tutor(int id, String name, String job) {
super(id, name, job);
}
//无set/get
//重写工作
@Override
public void work() {
System.out.println("助教正在工作");
}
}
package oopextends.text8;
public class Text {
public static void main(String[] args) {
Lecturer l = new Lecturer(1, "张三", "讲师");
l.work();
Maintainer m = new Maintainer(2, "李四", "维护人员");
m.work();
Tutor t = new Tutor(3, "王五", "助教");
t.work();
Buyer b = new Buyer(4, "赵六", "采购人员");
b.work();
}
}
1.7.3 物流快递运费计算
![![[Pasted image 20260422204236.png]]](https://i-blog.csdnimg.cn/direct/ae1bd921ed754f3093c96462f3757051.png)
package oopextends.text9;
public class Goods {
//属性
private String id;
private int weight;
private String name;
//构造方法
public Goods() {
}
public Goods(String id, int weight, String name) {
this.id = id;
this.weight = weight;
this.name = name;
}
//get/set
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public int getWeight() {
return weight;
}
public void setWeight(int weight) {
this.weight = weight;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
//行为
public int getPrice(){
return weight*10;
}
}
package oopextends.text9;
public class SameCity extends Goods{
//无特殊属性
//构造方法
public SameCity() {
}
public SameCity(String id, int weight, String name) {
super(id, weight, name);
}
//无get/set
//重写快递费
@Override
public int getPrice() {
return super.getPrice()+10;
}
}
package oopextends.text9;
public class AirSend extends Goods {
//无特殊属性
//构造方法
public AirSend() {
}
public AirSend(String id, int weight, String name){
super(id,weight,name);
}
//无get/set
//重写快递费
@Override
public int getPrice(){
return super.getPrice()+15;
}
}
package oopextends.text9;
public class text {
public static void main(String[] args) {
SameCity sameCity = new SameCity("123", 10, "张三");
System.out.println(sameCity.getPrice());
AirSend airSend = new AirSend("123", 10, "李四");
System.out.println(airSend.getPrice());
}
}
1.8 (扩展)继承的内存结构/字节码文件详解
1.8.1 继承的底层原理
- 子类能调用≠子类能继承
1.8.2 子类真正能继承父类的东西
- 构造方法: 不能被子类继承, 可以用super关键字调用
- 成员变量: 可以被子类继承, private私有的也可以, 但是私有的无法直接调用
- 成员方法: 虚方法可以被继承(虚方法: 普通成员方法, 非final/static/private修饰的方法 )
- final修饰的最终方法不能被继承, 可以被调用
编译期: 一级一级往上找, 遍历整个继承链, 确定要调用的方法在A类里, 记录该方法的地址
运行期: 直接原型编译时确定的方法, 虽然降低了编译的速度, 但是运行的速度会得到保证 - static修饰的静态方法不能被继承, 可以被调用
编译期: 一级一级的往上找, 遍历整个继承链, 确定要调用的方法在A里面, 将对象调用方法直接修改为类名的调用方法
运行期: 直接运行 - private修饰的私有方法不能被继承, 不能被调用
- 方法重写: 子类替换虚方法表里方法的地址值
- final修饰的最终方法不能被继承, 可以被调用
1.8.3 继承结构的内存图解
![![[Pasted image 20260423212325.png]]](https://i-blog.csdnimg.cn/direct/343c5d414d64465091e446c6a1d1cc2b.png)
1.9 Java中的权限修饰符
- 权限修饰符: 其实就是Java中的关键字, 用来控制一个成员被访问的范围
- 修饰的内容: 可以修饰成员变量, 成员方法, 构造方法… 等
![![[Pasted image 20260423220642.png]]](https://i-blog.csdnimg.cn/direct/0d6de2f283b34adea0622a335633952f.png)
- 作用范围从小到大(private<空着不写<protected<public)
更多推荐

所有评论(0)