好的,这是一篇根据你提供的讲义内容整理的博客文章,并添加了图标和去除了一些AI化的痕迹:
Java 面向对象进阶:深入理解继承、重写与 final 🛡️
在 Java 的面向对象世界里,继承是一个强大的特性,它允许我们创建基于现有类的“新”类,从而实现代码的复用和扩展。今天,我们将深入探讨继承的概念,学习方法重写以及 final
关键字的应用。
🌱 继承:代码复用的基石
- 作用:继承最直接的好处就是代码复用。通过继承,子类可以拥有父类的属性和方法,避免重复编写相同的代码。
- 实现方式:在 Java 中,使用
extends
关键字来实现继承。 - 父子关系:
- 超类 / 基类 / 父类:包含共有的属性和行为的类。
- 派生类 / 子类:在父类的基础上,拥有特有的属性和行为的类。
- 访问权限:派生类可以访问超类的成员变量和方法,以及派生类自己的成员。但是,超类不能访问派生类的成员。
- 单一继承:Java 只支持单一继承,也就是说,一个派生类只能直接继承一个超类。但一个超类可以有多个派生类。
- 传递性:继承具有传递性,如果类 C 继承类 B,类 B 继承类 A,那么类 C 也间接继承了类 A 的成员。
- 构造顺序:Java 规定,构造派生类之前必须先构造超类。
- 在派生类的构造方法中,如果没有明确调用超类的构造方法,编译器会默认调用超类的无参构造方法
super()
。 - 如果在派生类的构造方法中自己调用了超类的构造方法(使用
super(...)
),编译器就不再提供默认的无参构造方法调用。 - 注意:使用
super(...)
调用超类构造方法时,它必须是派生类构造方法中的第一条语句。
- 在派生类的构造方法中,如果没有明确调用超类的构造方法,编译器会默认调用超类的无参构造方法
🧱 super:父类的“代表”
super
关键字指代当前对象的超类对象。它主要用于在子类中访问被父类隐藏(例如同名)的成员。
super.成员变量名
:访问超类的成员变量。- 当超类成员变量和派生类成员变量同名时,
super
指代超类的成员,this
指代派生类的成员。 - 如果成员变量没有同名现象,那么写
super.
和this.
的效果是一样的(但为了清晰起见,通常访问自身成员用this.
, 访问父类成员用super.
)。
- 当超类成员变量和派生类成员变量同名时,
super.方法名()
:调用超类的方法。当子类重写了父类的方法,但又想调用父类的原始方法时,可以使用super.方法名()
。super()
:调用超类的构造方法。如前所述,必须放在派生类构造方法的第一行。
🔄 方法的重写 (Override):子类特有的实现
方法的重写发生在父子类之间。子类可以提供一个与父类方法具有相同名称、相同参数列表(也称为方法签名)的方法,从而覆盖父类的实现。
- 发生在父子类中。
- 方法名相同,参数列表相同。
- 重写方法被调用时,看对象的类型:创建的是哪个类的对象,就调用哪个类中定义的方法。这就是面向对象中的“多态性”的一种体现。简而言之:
new
谁,就调谁的。
🔒 final:不可改变的标记
final
关键字表示“最终的”、“不可改变的”。它可以修饰变量、方法和类。
- 修饰变量:被
final
修饰的变量,其值一旦被赋初值后就不能再被改变,通常用于定义常量。 - 修饰方法:被
final
修饰的方法不能被子类重写。 - 修饰类:被
final
修饰的类不能被其他类继承。
🐾 综合练习:模拟动物园
让我们通过一个模拟动物园的例子来展示继承和方法重写的应用。
public class Animal {
String name;
int age;
String color;
Animal(){
}
Animal(String name,int age,String color){
this.name = name;
this.age = age;
this.color = color;
}
void drink(){
System.out.println(color+"色的"+age+"岁的"+name+"正在喝水...");
}
void eat(){ // 父类的 eat 方法
System.out.println(color+"色的"+age+"岁的"+name+"正在吃饭...");
}
}
public class Dog extends Animal { // Dog 继承 Animal
Dog(){
}
Dog(String name,int age,String color){
super(name,age,color); // 调用父类的构造方法
}
// Dog 特有的方法
void lookHome(){
System.out.println(color+"色的"+age+"岁的狗狗"+name+"正在看家...");
}
// 重写父类的 eat 方法
void eat(){
System.out.println(color+"色的"+age+"岁的狗狗"+name+"正在吃肯头...");
}
}
public class Chick extends Animal { // Chick 继承 Animal
Chick(){
}
Chick(String name,int age,String color){
super(name,age,color); // 调用父类的构造方法
}
// Chick 特有的方法
void layEggs(){
System.out.println(color+"色的"+age+"岁的小鸡"+name+"正在下蛋...");
}
// 重写父类的 eat 方法
void eat(){
System.out.println(color+"色的"+age+"岁的小鸡"+name+"正在吃小米...");
}
}
public class Fish extends Animal { // Fish 继承 Animal
Fish(){
}
Fish(String name,int age,String color){
super(name,age,color); // 调用父类的构造方法
}
// 重写父类的 eat 方法
void eat(){
System.out.println(color+"色的"+age+"岁的小鱼"+name+"正在吃小虾...");
}
}
public class AnimalTest {
public static void main(String[] args) {
Dog dog = new Dog("小黑",2,"黑");
dog.eat(); // 调用 Dog 类中重写的 eat 方法
dog.drink(); // 调用 Animal 类中继承的 drink 方法
dog.lookHome(); // 调用 Dog 类特有的 lookHome 方法
System.out.println("---");
Chick chick = new Chick("小花",1,"花");
chick.eat(); // 调用 Chick 类中重写的 eat 方法
chick.drink(); // 调用 Animal 类中继承的 drink 方法
chick.layEggs(); // 调用 Chick 类特有的 layEggs 方法
System.out.println("---");
Fish fish = new Fish("小金",2,"金");
fish.eat(); // 调用 Fish 类中重写的 eat 方法
fish.drink(); // 调用 Animal 类中继承的 drink 方法
}
}
补充:
-
泛化与继承:从程序设计角度而言叫泛化,从代码实现角度而言叫继承。泛化就是继承,它们描述的是“is-a”的关系(例如:狗是一种动物)。
-
继承的内容:子类继承的是父类的成员变量和普通方法,不包括构造方法。父类的构造方法是被子类通过
super()
来调用的。 -
重写 vs 重载:这是一个常见的面试题!
- 重写 (overriding):发生在父子类中,方法名相同,参数列表相同。
- 重载 (overloading):发生在同一类中,方法名相同,参数列表不同。
重载特例情况:
class Aoo{ void show(){ // 无参 show 方法 } } class Boo extends Aoo{ // Boo 继承了 Aoo 的 show() 方法 // 在此类中定义了一个新的 show() 方法,参数列表不同,发生了 show() 的重载 void show(String name){ // 有参 show 方法 } }
总结
- 继承:
- 作用:代码复用
- 特点:单- -继承、賄传递性
- super关键字:
- 指代当前对象的父类对象
- 方法的重写:
- 发生在父子类中,方法名相同,参数列表相同
- 重写方法被调用时,看对象的类型调用方法
- final: 最终的、不可改变的
- 变量不能被改变、方法不能被重写、类不能被继承
小提示
- 继承的作用是什么?继承的应用场景是什么?
- 继承的特点.
- super与继承的关系
- 方法重写的应用场景
- java中哪些类是final的