当前位置: 首页 > news >正文

JavaSE 基础语法 - 继承 - ②

接上节 JavaSE 基础语法 - 继承 - ① 的内容。

子类不仅可以拥有父类的成员变量,也可以拥有父类的方法。

那么新的问题来了。

如果:子类自己也有:String name ,这时候怎么办?如果子类自己也有:eat(),又怎么办?

如果子类构造对象的时候,需要先初始化父类,应该怎么办?

Java 为了解决这些问题,引入了:super关键字。

8、为什么需要 super

第一次学习继承的时候,应该都有一个疑惑:子类已经继承了父类,为什么还需要 super?

其实,super的出现并不是为了增加一种新的语法,而是为了解决继承过程中"成员冲突"和"父类初始化"的问题。

8.1 子类为什么需要访问父类

假设有一个 Person 类:

classPerson{Stringname="张三";publicvoideat(){System.out.println("Person 正在吃饭");}}

定义 Student:

classStudentextendsPerson{publicvoidstudy(){System.out.println("学习");}}

测试:

Studentstu=newStudent();System.out.println(stu.name);stu.eat();

输出:

张三Person正在吃饭

这是没有问题的。

因为 Student 没有 name ,也没有 eat() 。

Java自然向父类查找。

但是,如果 Student 自己也定义:

classStudentextendsPerson{Stringname="李四";// 自己也定义有了name}

测试:

Studentstu=newStudent();System.out.println(stu.name);

输出:

李四

为什么?因为:成员变量遵循就近原则

那么问题来了,如果我就是想访问 Person 里面那个 name ,怎么办?

Java于是设计了super,专门表示父类对象部分

8.2 为什么会出现成员重名

再来看一个例子。

Person:

classPerson{Stringname="张三";}

Student:

classStudentextendsPerson{Stringname="李四";}

对象实际上应该长这样:

很多同学看到这里会问:一个对象里面怎么会有两个 name?答案是:可以。

因为父类部分属于 Person ,子类部分属于 Student 。

它们分别存储。只是访问的时候遵循:先找子类,再找父类

因此 stu.name 得到李四,而父类那个张三仍然存在,只是访问不到,所以Java设计super

表示:访问父类中的 name

8.3 super 诞生的原因

现在我们已经知道对象实际上包含:父类部分 + 子类部分。

因此Java需要一种方式告诉 JVM:不要找子类,请直接访问父类

于是有了super,可以把 super 理解成:父类对象部分的引用

例如:

super.name 表示 Person中的name,不是 Student自己的name。

同样 super.eat() 表示调用父类的方法。而不是子类自己的方法。

另外,super() 表示调用父类构造方法。

所以 super 实际上有三种用途:

  • super.成员变量

  • super.成员方法

  • super()

9、super 关键字

9.1 什么是 super

super是 Java 提供的一个关键字。它表示:当前对象中的父类部分

很多人会把 super 理解成父类对象,这种说法并不准确。

因为程序中并没有重新创建一个父类对象。

真正存在的是只有一个对象,这个对象里面存着父类部分还有子类部分。

所以,更准确的理解:super 用来引用当前对象中的父类部分

例如:

classPerson{Stringname="张三";}classStudentextendsPerson{Stringname="李四";publicvoidprint(){System.out.println(name);System.out.println(super.name);}}

输出:

李四 张三

说明:name 访问子类,而 super.name 访问的是父类。

9.2 super 访问成员变量

这是 super 最简单的用法。

例如:

classPerson{Stringname="张三";}classStudentextendsPerson{Stringname="李四";publicvoidshow(){System.out.println(name);System.out.println(super.name);}}

测试:

Studentstu=newStudent();stu.show();

输出:

李四 张三

因此:super 可以解决成员变量隐藏的问题。

9.3 super 访问成员方法

不仅成员变量可以重名,成员方法也可以。

例如:

classPerson{publicvoideat(){System.out.println("Person 吃饭");}}classStudentextendsPerson{@Overridepublicvoideat(){System.out.println("Student 吃饭");}publicvoidtest(){eat();super.eat();}}

测试:

Studentstu=newStudent();stu.test();

输出:

Student吃饭Person吃饭

解释:

  • eat():调用当前类(Student)的实现。
  • super.eat():调用父类(Person)的实现。

这种写法在方法重写中非常常见,例如子类希望在保留父类逻辑的基础上扩展功能:

@Overridepublicvoideat(){super.eat();// 执行父类逻辑System.out.println("饭后散步");}

9.4 super 调用父类构造方法

除了访问成员变量和成员方法,super 还有第三种用途:调用父类构造方法

例如:

classPerson{publicPerson(){System.out.println("Person 构造方法");}}classStudentextendsPerson{publicStudent(){super();System.out.println("Student 构造方法");}}

测试:

newStudent();

输出:

Person构造方法Student构造方法

可以看到创建子类对象时:父类构造方法一定先执行

为什么?因为:子类对象中包含父类部分

只有先完成父类部分初始化,才能继续初始化子类部分。

9.5 super 使用注意事项

使用 super 时,需要记住以下几点:

1、super 可以访问父类成员变量、成员方法和构造方法

super.name;super.eat();super();

2、super() 只能出现在构造方法中

错误示例:

publicvoidtest(){// 这是一个普通的的方法,不是构造方法super();}

编译错误。

3、super() 必须是构造方法中的第一条语句

正确:

publicStudent(){super();System.out.println("Student");}

错误:

publicStudent(){System.out.println("Hello");super();}

编译错误。

4、this() 与 super() 不能同时出现

例如:

publicStudent(){this("Tom");super();}

编译错误。

原因是:

  • this() 用于调用本类其他构造方法。
  • super() 用于调用父类构造方法。
  • 两者都必须位于构造方法第一行,因此不能同时出现。

10、this 与 super

学习完 super 之后,都会有一个疑问:this 和 super 到底有什么区别?

例如:

this.namesuper.name到底有什么不同?

再比如:

this();super();为什么都必须写在构造方法第一行?

10.1 什么是 this

在前面,我们已经讲过:this表示当前对象的引用。

例如:

classStudent{Stringname="张三";publicvoidprint(){System.out.println(this.name);}}

这里的this.name表示当前Student对象中的name

10.2 什么是 super

super表示:当前对象中的父类部分。

例如:

classPerson{Stringname="父类";}classStudentextendsPerson{Stringname="子类";}

this.name得到的是子类,而super.name得到父类

10.3 this 与 super 相同点

两者都有引用作用。

都不能脱离对象。

例如下面都可以访问成员变量:

this.name;super.name;

都可以访问成员方法:

this.eat();super.eat();

都可以调用构造方法:

this();super();

因此它们都属于Java提供的特殊引用。

10.4 this 与 super 不同点

虽然写法非常相似。

但是作用完全不同。

this表示当前对象。

例如:

this.name的查找,会先在子类中查找,子类没有才去父类。

super.name的查找,会直接在父类中查找,不会在子类。

因此两者访问对象不同。

10.5 this 与 super 对比表

对比项thissuper
表示对象当前对象当前对象中的父类部分
访问成员变量
访问成员方法
调用构造方法
调用位置普通方法、构造方法普通方法、构造方法(super()仅构造方法)
是否必须第一行this()必须super()必须
是否可同时出现

注意:

this 和 super(成员访问)可以同时出现:

publicvoidtest(){System.out.println(this.name);System.out.println(super.name);// 这样是可以同时使用}

但 this() 和 super() 不能同时出现,因为两者都必须位于构造方法第一行。

10.6 使用场景

场景一:访问当前对象成员

this.name

场景二:访问父类成员

super.name

场景三:调用当前类其他构造方法

this("张三");

场景四:调用父类构造方法

super();

这是最常见也是最重要的使用方式。

11、protected 访问权限

之前我们介绍了四种访问权限:

  • public
  • protected
  • 默认(default)
  • private

但是当时并没有详细介绍protected

因为它真正发挥作用是在继承。

11.1 为什么需要 protected

先来看一个例子。

Person:

classPerson{privateStringname;}

Student:

classStudentextendsPerson{publicvoidshow(){System.out.println(name);}}

编译报错,因为 private 只能本类访问。

如果改成protected String name;

Student 立即可以访问。

因为 protected 就是专门为继承设计。

11.2 protected 访问规则

protected 允许下面两种情况:

  • 同一个包

  • 不同包

例如:

1、都在同一个包中,可以访问;

2、分别在不同包,但是需要继承关系才可以访问;

3、如果分别在不同包,也没有继承关系的话,就不能访问。

11.3 同包访问

例如:

protectedintage;

同一个包任何类都可以访问。

例如:

Studentstu=newStudent();System.out.println(stu.age);

合法。

11.4 不同包继承访问

例如:

Person 位于 com.person,

Student 位于 com.student,

只要:class Student extends Person

仍然可以访问:age

这也是 protected 最大的作用。

11.5 四种访问权限总结

这是Java面试经常考的。

修饰符本类同包不同包子类其他包
public
protected
default
private

12、构造方法

我们已经讲过构造方法。

那么在继承以后,构造方法又会发生什么变化?

来看下面例子。

12.1 父类构造方法

classPerson{publicPerson(){System.out.println("Person");}}

12.2 子类构造方法

classStudentextendsPerson{publicStudent(){System.out.println("Student");}}

测试:

newStudent();

很多人猜输出:

Student

实际上输出:

PersonStudent

因为创建Student对象。

首先必须完成:

Person部分初始化。

因此父类构造方法一定先执行。

12.3 默认 super()

我们发现代码没有写super(),父类构造方法还是会执行。

原因:

Java自动补充:

publicStudent(){super();System.out.println("Student");}

因此即使没有写,仍然调用父类构造方法。

12.4 显示调用 super()

如果父类只有有参构造。

例如:

classPerson{publicPerson(Stringname){}}

那么必须自己写:

super("张三");

否则编译报错。

12.5 为什么 super() 必须放第一行

这是Java规定的。

原因:

只有父类初始化完成,子类才能继续初始化。

否则子类可能使用一个尚未初始化完成的父类成员。

因此Java从语言层面规定:super() 必须位于构造方法第一行

13、对象初始化过程

前面我们已经知道,子类对象中实际上包含两部分:

父类部分+子类部分

例如:

classPerson{Stringname;intage;}classStudentextendsPerson{intscore;}

创建:

Studentstu=newStudent();

此时 stu 所代表的对象中,可以理解为包含:

Person部分 name ageStudent部分 score

那么问题来了:创建 Student 对象时,父类部分和子类部分到底谁先初始化?

答案是:先初始化父类部分,再初始化子类部分

也就是说:

创建Student对象 ↓ 初始化Person部分 ↓ 执行Person构造方法 ↓ 初始化Student部分 ↓ 执行Student构造方法 ↓ 对象创建完成

但是,真正的初始化过程比这个更加详细。

13.1 成员变量默认初始化

当 JVM 为对象分配内存后,对象中的成员变量会先获得默认值。

例如:

classPerson{Stringname;intage;booleanflag;}

创建:

Personp=newPerson();

此时成员变量会先获得默认值:

name->nullage->0flag->false

注意:这里说的是成员变量。

局部变量不会自动进行默认初始化。

例如:

publicstaticvoidmain(String[]args){intage;System.out.println(age);}

会编译错误。

所以:

成员变量->有默认值 局部变量->必须手动初始化

13.2 成员变量显式初始化

如果成员变量在定义的时候进行了初始化:

classPerson{Stringname="张三";intage=18;}

那么在默认初始化之后,显式初始化按照成员变量在类中定义的顺序依次执行。

可以简单理解为:

name →nullage →0先执行默认初始化 然后再到下边的赋值 name →"张三"age →18

13.3 父类部分先初始化

假设:

classPerson{Stringname="Person";publicPerson(){System.out.println("Person 构造方法");}}classStudentextendsPerson{Stringschool="Java";publicStudent(){System.out.println("Student 构造方法");}}

执行:

Studentstu=newStudent();

首先处理的是:

Person部分

也就是:

name 默认初始化 ↓ name 显式初始化为"Person"Person构造方法

然后才开始处理:

Student部分

13.4 子类部分再初始化

接下来处理 Student 部分:

Stringschool="Java";

先进行默认初始化:

school->null

然后进行显式初始化:

school->"Java"

最后执行 Student 构造方法:

publicStudent(){System.out.println("Student 构造方法");}

所以整个过程可以理解为:

Person部分 默认初始化->显式初始化->Person构造方法
Student部分 默认初始化->显式初始化->Student构造方法

14、综合案例

下面通过一个完整案例,把 super、构造方法和对象初始化过程结合起来。

14.1 定义 Person

classPerson{protectedStringname="Person";protectedintage=20;publicPerson(){System.out.println("Person 无参构造方法");}publicPerson(Stringname,intage){this.name=name;this.age=age;System.out.println("Person 有参构造方法");}publicvoideat(){System.out.println("Person 吃饭");}}

14.2 定义 Student

classStudentextendsPerson{privatedoublescore=100;publicStudent(Stringname,intage,doublescore){super(name,age);this.score=score;System.out.println("Student 构造方法");}@Overridepublicvoideat(){super.eat();System.out.println("Student 吃饭");}publicvoidshow(){System.out.println("姓名:"+this.name);System.out.println("年龄:"+this.age);System.out.println("成绩:"+this.score);}}

14.3 测试

publicclassTest{publicstaticvoidmain(String[]args){Studentstu=newStudent("张三",18,95);stu.show();stu.eat();}}

运行结果:

Person有参构造方法Student构造方法 姓名:张三 年龄:18成绩:95.0Person吃饭Student吃饭

14.4 分析对象创建过程

执行:

Studentstu=newStudent("张三",18,95);

首先创建 Student 对象,然后进入 Student 构造方法:

publicStudent(Stringname,intage,doublescore){super(name,age);this.score=score;System.out.println("Student 构造方法");}

第一条语句:

super(name,age);

调用:

Person(Stringname,intage)

所以父类部分得到:

name="张三"age=18

然后返回到 Student 构造方法,又执行:

this.score=score;

得到:

score=95

最后输出:

Student构造方法

14.5 分析 super.eat()

执行:

stu.eat();

Student 中重写了:

publicvoideat(){super.eat();System.out.println("Student 吃饭");}

首先:

super.eat();

调用父类:

Person.eat()

输出:

Person吃饭

然后执行:

System.out.println("Student 吃饭");

输出:

Student吃饭

最终:

Person吃饭Student吃饭

这是一种非常典型的继承使用方式:子类重写父类方法,同时通过 super 保留父类原有功能,再增加自己的功能

http://www.jsqmd.com/news/1400832/

相关文章:

  • 手术室液体加温箱:原理、应用与选购指南
  • AI应用成本优化实战:从60亿消耗零收入案例看LLM经济学
  • 2026年上海GEO代运营服务选购全指南 - 筑云鲸
  • 哲学与编程的认知革命:从维特根斯坦到Python实践
  • Swagger Codegen 实战指南:从 OpenAPI 规范到多语言代码生成
  • 微信小程序订阅消息开发全解析:从用户手势调用到后端发送实践
  • 你的 sys.argv 为何总“认错”参数?——命令行解析中引号与转义的致命陷阱与避坑指南
  • 2026年上海GEO代运营公司选型对比指南 - 筑云鲸
  • STM32 Boot模式详解:从启动原理到IAP应用实战
  • Python爬虫入门:BeautifulSoup解析HTML与数据提取实战
  • 解决Python SSL模块不可用错误:从原理到实战修复指南
  • Dify 中级实验(08):代码节点进阶——如何用标准库处理文件与数据?
  • 数值转换:从底层原理到实战应用,解决数据处理的精度与格式难题
  • 硬件与软件的协调,参考b站黑马程序员
  • 2026年8月市场上技术好的采暖炉实力厂家选哪家,空气能锅炉/燃油锅炉/蒸发器/采暖炉/蒸汽锅炉/锅炉,采暖炉厂家找哪家 - 企业权威推荐大使
  • SAM胡诌
  • 第 7 篇:「Fluss 状态外部化」—— Delta Join 与 Aggregation Merge Engine
  • NVIDIA Nemotron 3.5 Lightning:专为高效推理优化的开源大语言模型部署实战
  • Git代码合并与冲突解决实战技巧
  • Dify 中级实验(07):子工作流——如何把公共逻辑做成可复用积木?
  • 基于Human Behavior分析的AI原生应用设计:从行为流协同到工程实践
  • Python开发轻量级员工管理系统的实践与优化
  • 最长公共前缀算法精解:横向与纵向扫描的实战剖析
  • AtCoder Beginner Contest 471 ABCDE
  • 中美Robotaxi“四国杀”:2026,谁在领跑万亿出行终局?
  • Gitee高人气开源项目深度解析:从筛选到源码学习的全链路指南
  • AOSP-- 第 2 章:源码与构建系统
  • IDEA中git stash可视化操作指南:提升多任务开发效率
  • 学习25
  • 从2020亚太赛A题看数学建模:数据驱动与机理分析的融合实践