第五章 继承与多态
5.1 继承
继承是面向对象编程中的一个基本特性,它允许创建基于现有类的新类,从而促进代码的复用和扩展。
5.1.1 继承概述
在Java中,当一个类继承另一个类时,它将获取超类(父类)的所有属性和方法。这样的类称为子
class Animal {
void eat() {
System.out.println("Animal eats");
}
}
class Dog extends Animal {
void bark() {
System.out.println("Dog barks");
}
}
5.1.2 子类的继承规则
子类继承超类时,必须遵守Java语言规定的一些规则:
- 子类只能继承超类的非private成员(属性和方法)。
- 子类不能继承超类的构造方法,但可以通过super()调用。
5.1.3 子类对象的创建和super
创建子类的对象时,会先调用父类的构造方法。super
关键字可以用来调用父类构造方法,以及父类中被子类覆盖的方法。
class Animal {
Animal() {
System.out.println("Animal is created");
}
}
class Dog extends Animal {
Dog() {
super(); // Call the superclass constructor
System.out.println("Dog is created");
}
}
5.1.4 继承关系中的内存分配
在继承关系中,当子类对象被创建时,内存中会为包含的父类成员分配空间,以便使用父类的属性和方法。
5.1.5 实例变量的隐藏
当子类和父类具有相同名称的实例变量时,子类的实例变量会隐藏父类的实例变量。
class Animal {
String name = "Animal";
}
class Dog extends Animal {
String name = "Dog";
void display() {
System.out.println(name); // prints "Dog"
System.out.println(); // prints "Animal"
}
}
5.1.6 方法重写和方法重载
- 方法重写(Override):子类提供超类中某个方法的特定实现版本。
- 方法重载(Overload):在一个类中定义多个方法名相同,但参数不同的方法。
class Animal {
void eat() {
System.out.println("Animal eats");
}
}
class Dog extends Animal {
@Override
void eat() {
System.out.println("Dog eats");
}
}
5.1.7 子类对父类类成员的访问
子类可以访问父类的所有非private成员。如果需要访问隐藏的成员或调用被覆盖的方法,可以使用super
关键字。
概念与描述表格:
概念 | 描述 | 代码示例 |
---|---|---|
子类对象的创建和super | 子类构造方法创建时,会隐式或显式地调用父类的构造方法 | class Dog extends Animal { Dog() { super(); } } |
继承关系中的内存分配 | 创建子类对象时,会为父类成员分配内存空间,以便可以使用它们 | 表述概念,不直接对应代码示例 |
实例变量的隐藏 | 子类可以定义与父类同名的实例变量,此时父类的变量被隐藏 | class Dog extends Animal { String name = "Dog"; void display() { System.out.println(); } } |
方法重写和方法重载 | 重写是子类提供父类方法的特定实现。重载是定义名称相同但参数列表不同的方法 | 重写:class Dog extends Animal { @Override void eat() { ... } } 重载:在同一类中 void eat() { ... } void eat(String food) { ... } |
子类对父类成员的访问 | 子类可以访问父类的所有非private成员,必要时可以使用super关键字访问被隐藏的成员或被覆盖的方法 | class Dog extends Animal { void display() { System.out.println(); } } |
5.2 引用类型的转换
在Java中,类的引用变量可以表示该类的对象或该类的子类对象。
5.2.1 上转型
将子类类型的引用转为超类类型称为上转型,它总是安全的,因为子类对象总是也是一个超类对象。
Animal a = new Dog(); // 发生上转型
5.2.2 下转型
将超类引用转为子类引用称为下转型。必须显式进行,并且必须确保转型是安全的。
Animal a = new Dog();
Dog d = (Dog)a; // 发生下转型
转换类型 | 描述 | 是否安全 | 示例 |
---|---|---|---|
上转型 | 子类转换成父类 | 安全 | Animal a = new Dog(); |
下转型 | 父类转换成子类 | 需要确保安全 | Dog d = (Dog)a; |
5.3多态
多态是指允许不同类的对象对同一消息作出响应。在Java中,多态的实现是通过超类引用变量可以引用子类对象来实现的。
5.3.1 静态多态
静态多态,也称为编译时多态性,通常是通过方法重载来实现的,即在同一个类中创建多个同名方法,但是它们各自的参数列表必须不同。
class Calculator {
int add(int a, int b) {
return a + b;
}
double add(double a, double b) {
return a + b;
}
}
5.3.2 动态多态
动态多态,又称为运行时多态性,通过方法重写实现,即子类提供一个特定的实现,该实现覆盖了父类的方法。
class Animal {
void speak() {
System.out.println("The animal speaks");
}
}
class Dog extends Animal {
void speak() {
System.out.println("The dog barks");
}
}
public class DynamicPolymorphismExample {
public static void main(String[] args) {
Animal myAnimal = new Animal();
Animal myDog = new Dog(); // 通过动态多态使用Dog类
myAnimal.speak();
myDog.speak(); // 输出:The dog barks
}
}
5.3.3 引用回调
引用回调指的是当子类的引用被传递到通过超类类型参数的方法中去,该方法可以根据实际对象类型调用对应的重写方法。
class Animal {
void speak() {
System.out.println("Animal speaks");
}
}
class Cat extends Animal {
void speak() {
System.out.println("Cat meows");
}
}
public class CallbackExample {
static void performSpeak(Animal animal) {
animal.speak(); // 引用回调
}
public static void main(String[] args) {
Animal myCat = new Cat();
performSpeak(myCat); // 输出:Cat meows
}
}
5.4 final修饰符
final关键字用于声明属性、方法和类,以指示它们不能被更改或继承。
5.4.1 final类
当用final修饰一个类时,表明这个类不能被继承。
final class FinalClass {
void display() {
System.out.println("This is a final class and cannot be inherited.");
}
}
5.4.2 final方法
当用final修饰一个方法时,这个方法不能在子类中被重写。
class Base {
final void show() {
System.out.println("This is a final method and cannot be overridden.");
}
}
5.4.3 final变量
当一个变量被声明为final,它就成了常量,不能被再次赋值。
class Constants {
public static final int NUM = 5;
}
public class FinalVariableExample {
public static void main(String[] args) {
System.out.println(Constants.NUM); // 输出:5
}
}
概念 | 描述 | 是否可变 | 代码示例 |
---|---|---|---|
final类 | 类不能被继承 | 否 | final class FinalClass { ... } |
final方法 | 方法不能被子类重写 | 否 | class Base { final void show() {...} } |
final变量 | 变量值一经赋值后不能变 | 否 | public static final int NUM = 5; |
5.5 Object类
Object类是Java中所有类的超类,每个类都使用Object作为超类。所有对象(包括数组)都实现这个类的方法。
5.5.1 Object类方法概述
Object类提供了一些基本方法,例如:
clone()
— 用于复制对象。equals(Object obj)
— 指示一些其他对象是否“相等于”此对象。hashCode()
— 返回对象的哈希码值。toString()
— 返回对象的字符串表示。getClass()
— 返回对象运行时的类对象。notify(), notifyAll(), wait()
— 与对象监视器配合,实现线程间同步。
class Person {
private String name;
Person(String name) {
= name;
}
@Override
public boolean equals(Object obj) {
if (obj instanceof Person) {
Person p = (Person) obj;
return name.equals();
}
return false;
}
@Override
public int hashCode() {
return name.hashCode();
}
@Override
public String toString() {
return "Person: " + name;
}
}
通过覆盖这些方法,可以使类更容易使用,更容易与其他类相互操作。
第六章 抽象类与接口
6.1 抽象类
抽象类是不能实例化的类,它可能包含抽象方法。抽象方法是没有实现的方法,它们必须在子类中被重写。
6.1.1 抽象方法
抽象方法是只有方法声明没有方法体的方法。如果一个类包含抽象方法,那么该类必须被声明为抽象的。
abstract class Animal {
abstract void speak();
}
class Dog extends Animal {
@Override
void speak() {
System.out.println("The dog barks");
}
}
6.1.2 抽象类概述
抽象类是一种不能被实例化,只能被继承的类。如果一个类被声明为抽象的,它就不可以创建对象。
abstract class AbstractClass {
abstract void display();
}
class ConcreteClass extends AbstractClass {
void display() {
System.out.println("This is a concrete implementation of an abstract class");
}
}
抽象类通常作为多个类的共同基类,它们的共同特点被提取出来形成抽象类。
6.2 接口
接口是完全抽象的类,它允许声明哪些方法必须由实现该接口的类来定义。
6.2.1 接口的定义
接口中可以定义抽象方法和默认方法,以及静态方法和常量。从Java 8开始,接口也可以包含默认方法和静态方法具体实现。
interface MyInterface {
// 抽象方法
void doSomething();
// 默认方法
default void defaultMethod() {
System.out.println("This is a default method");
}
// 静态方法
static void staticMethod() {
System.out.println("This is a static method");
}
}
6.2.2 类与接口的关系
一个类可以实现多个接口。实现接口的类必须提供接口中所有声明的方法的具体实现。
class MyClass implements MyInterface {
public void doSomething() {
System.out.println("Doing something...");
}
}
6.2.3 访问接口中的常量
接口中定义的任何字段自动是public, static, final的。
interface Constants {
int MIN = 0;
int MAX = 10;
}
public class ConstantsAccess {
public static void main(String[] args) {
int threshold = Constants.MAX; // 直接访问接口中的常量
}
}
6.2.4 接口和接口的关系
接口可以继承其他接口,并可以添加新的抽象方法和常量。
interface A {
void myMethod();
}
interface B extends A {
void myOtherMethod();
}
概念 | 描述 | 示例 |
---|---|---|
Object类 | 所有类的超类 | 常用方法如toString() , equals() |
抽象类 | 不能实例化的类 | abstract class Animal { abstract void speak(); } |
抽象方法 | 没有实现的方法 | abstract void speak(); |
接口 | 定义一组抽象方法 | interface MyInterface { void doSomething(); } |
类与接口的关系 | 类实现接口必须定义所有接口方法 | class MyClass implements MyInterface { ... } |
访问接口中的常量 | 接口的常量是public, static, final的 | int max = Constants.MAX; |
接口继承 | 接口可以继承一个或多个其他接口 | interface B extends A |