思维导图:

第4章 面向对象(下)
学习目标:
- 了解面向对象中的继承特性,掌握继承的概念与特点。
- 掌握方法的重写,能够在子类中重写父类方法。
- 掌握
super
关键字,明白如何在类中使用super
访问父类成员。 - 理解
final
关键字的作用,知道如何使用final
修饰类、方法和变量。 - 熟悉抽象类的定义与使用。
- 理解接口的定义,能独立编写接口。
- 掌握多态性,知道如何利用对象类型转换解决继承中的多态问题。
- 了解
Object
类及其常用方法。 - 熟悉内部类及其四种形式的特点。
继续学习: 第3章已经介绍了面向对象的基础用法以及封装性。本章将进一步深入探讨继承和多态。
4.1 继承
4.1.1 继承的概念
-
现实与编程的对应:
- 现实中的继承:子女继承父辈的财产、事业等。
- 编程中的继承:描述事物间的从属关系。例如,猫和狗都是动物,可以说猫和狗继承自动物类。
-
示例:
- 动物(Animal)
- 猫(Cat)
- 波斯猫(PersianCat)
- 巴厘猫(BalineseCat)
- 狗(Dog)
- 沙皮狗(SharPeiDog)
- 斑点狗(DalmatianDog)
- 猫(Cat)
- 动物(Animal)
-
Java中的继承:
- 子类自动继承父类的属性和方法。
- 使用
extends
关键字表示继承。
class 父类 {
// ...
}
class 子类 extends 父类 {
// ...
}
4.1.2 示例解析
在Example01.java
文件中:
Animal
类定义了name
,age
, 和COLOR
属性,以及相应的getter
和setter
方法。Dog
类继承自Animal
类,因此可以访问Animal
类的属性和方法。- 在
main
方法中,我们创建了Dog
类的对象并设置了其name
和age
属性的值,然后输出了这些值。
结果表明,尽管子类Dog
没有明确定义任何属性和方法,但它能够继承并使用来自父类Animal
的属性和方法。
4.1.3 继承的扩展
子类不仅可以继承父类的特性,还可以添加自己的特性。
在Example02.java
中:
- 我们对
Dog
类进行了扩展,添加了一个新的color
属性以及相应的getter
和setter
方法。
这说明,在子类中,我们可以保留父类的特性的同时添加新的特性。
-
文件4-2的内容
- Dog类继承:在文件4-2中,Dog类继承了Animal类的属性和方法。
- 新增属性:Dog类增加了颜色(color)的getter和setter方法。
- 示例代码:在main()方法中,通过dog对象分别调用Animal和Dog类的setter方法来设置名称、年龄和颜色。接着,调用getter方法来获取这些属性值。
- 运行结果:输出“名称:牧羊犬,年龄:3,颜色:黑色”。
-
继承中的权限注意事项
- 子类可以继承父类的成员和方法。
- 但子类只能访问使用
public
和protected
修饰的属性和方法。 - 使用
default
和private
修饰的属性和方法不能被子类访问。
-
类继承中的几个关键点:
- 单继承原则:在Java中,每个类只能直接继承一个父类。例如,一个类不能同时继承A类和B类。
- 多类继承同一父类:多个子类可以共同继承同一个父类。例如,B类和C类都可以继承A类。
- 多层继承:Java支持多层继承。例如,C类可以继承B类,而B类又继承A类。在这种情况下,C类即是B类的子类,也是A类的子类。
- 父类和子类的相对性:在Java中,父类和子类的概念是相对的。一个类可能是另一个类的父类,同时也可能是其他类的子类。
4.1.2 方法的重写
重写的概念
在面向对象的编程中,当子类继承父类后,会自动继承父类的所有方法。但在某些情境下,子类可能需要对其继承的方法进行修改或调整。这个过程被称为“方法的重写”。
要点:
- 方法重写也被称为覆盖。
- 重写的方法和被重写的方法必须有相同的方法名、参数列表和返回值类型。
方法的重写实例
考虑以下代码示例:
// 定义Animal类
class Animal {
// 定义动物叫的方法
void shout() {
System.out.println("动物发出叫声");
}
}
// 定义Dog类,继承Animal类
class Dog extends Animal {
// 重写父类Animal的shout()方法
void shout() {
System.out.println("汪汪汪……");
}
}
// 定义测试类
public class Example03 {
public static void main(String[] args) {
Dog dog = new Dog(); // 创建Dog类的实例对象
dog.shout(); // 调用Dog类重写的shout()方法
}
}
此代码的运行结果为“汪汪汪……”。
注意点
- 方法重写的目的是为了让子类具有更具体或与父类不同的行为。
- 子类重写父类方法时,不能使用比父类方法更严格的访问权限。例如,如果父类的方法是public,那么子类重写的方法不能是private。
思考与总结
- 通过方法重写,子类可以继承父类的功能,同时还可以根据自己的需要对这些功能进行改进或扩展。
- 在Java中,方法的重写是多态的一个关键组成部分,允许程序在运行时动态地选择应该调用哪个方法。
- 当子类的对象调用一个被重写的方法时,它总是调用子类中的版本,而不是父类中的版本。
提示
当重写一个方法时:
- 保持方法签名的一致性(即相同的方法名、参数列表和返回类型)。
- 不要在子类中使用比父类中被重写的方法更严格的访问权限。
4.1.3 super
关键字
介绍
当子类重写父类的方法后,子类对象将无法访问父类中被子类重写过的方法。为了解决这个问题,Java提供了super
关键字,使用super
关键字可以在子类中访问父类的非私有方法、非私有属性以及构造方法。
使用super
关键字访问父类的属性和方法
-
格式:
super.属性 super.方法(参数1, 参数2, ...)
-
案例:如文件4-5所示,
Dog
类通过super
关键字访问父类Animal
的shout()
方法和name
属性。// 定义Animal类 class Animal { String name = "牧羊犬"; void shout() { System.out.println("动物发出叫声"); } } // 定义Dog类,继承Animal类 class Dog extends Animal { public void shout() { super.shout(); System.out.println("汪汪汪……"); } public void printName() { System.out.println("名字:" + super.name); } } // 测试类 public class Example05 { public static void main(String[] args) { Dog dog = new Dog(); dog.shout(); dog.printName(); } }
运行结果:动物发出叫声,汪汪汪……,名字:牧羊犬
使用super
关键字调用父类的构造方法
-
格式:
super(参数1, 参数2, ...)
-
案例:如文件4-6所示,
Dog
类通过super
关键字调用父类Animal
的有参构造方法。// 定义Animal类 class Animal { private String name; private int age; public Animal(String name, int age) { this.name = name; this.age = age; } public String info() { return "名称:" + this.name + ", 年龄:" + this.age; } } // 定义Dog类,继承Animal类 class Dog extends Animal { private String color; public Dog(String name, int age, String color) { super(name, age); this.color = color; } @Override public String info() { return super.info() + ", 颜色:" + this.color; } } // 测试类 public class Example06 { public static void main(String[] args) { Dog dog = new Dog("牧羊犬", 3, "黑色"); System.out.println(dog.info()); } }
运行结果:名称:牧羊犬,年龄:3, 颜色:黑色
注意事项
- 使用
super
调用父类构造方法的代码必须位于子类构造方法的第一行。 - 使用
this
和super
调用构造方法代码都要求必须放在构造方法的首行,所以不能同时出现。
super
与this
关键字的对比
区别点 | super | this |
---|---|---|
访问属性 | 直接访问父类中的非私有属性 | 访问本类中的属性,如果本类中没有该属性,则从父类中继续查找 |
调用方法 | 直接调用父类中的非私有方法 | 调用本类中的方法,如果本类中没有该方法,则从父类中继续查找 |
调用构造方法 | 调用父类构造方法,必须放在子类构造方法的首行 | 调用本类构造方法,必须放在构造方法的首行 |
总结:
4.1 继承的重点:
- 继承的定义:继承是 Java 面向对象的一个核心机制,它允许一个类继承另一个类的属性和方法。
- 关键字
extends
:在 Java 中,使用extends
关键字来表示一个类继承另一个类。 - 父类和子类:在继承中,被继承的类称为父类或超类,继承父类的类称为子类。
- 方法的重写:子类可以重写父类的方法,以提供特定于其自身的实现。
super
关键字:在子类中,super
关键字被用来引用父类的成员(方法、属性)和构造器。
难点:
- 方法重写的规则:在重写方法时,必须保持方法签名(方法名称和参数列表)相同,并且子类的方法不能降低父类方法的访问权限。
- 使用
super
关键字:理解何时以及如何正确使用super
关键字来调用父类的构造器或方法可能需要实践。 - 构造器和继承:父类的构造器不被子类继承,但子类的构造器必须(显式或隐式)调用父类的构造器。
易错点:
- 访问修饰符的误用:尝试访问父类的
private
成员或降低重写方法的访问权限时会导致错误。 - 忘记调用父类的构造器:如果父类没有默认的无参数构造器,并且在子类的构造器中没有显式调用父类的构造器,这会导致编译错误。
super
和this
的混淆:混淆它们的用途或在同一构造器中同时使用它们(因为它们都需要在构造器的首行)可能导致错误。- 方法隐藏:如果子类中定义了一个与父类中同名但参数不同的方法,这不是重写,而是方法的隐藏,有时可能会导致预期之外的行为。
综上,理解和应用 Java 的继承机制需要时间和实践,但它为创建模块化和可重用的代码提供了强大的工具。