Java 抽象类 相关知识点
1. 抽象类的定义与语法
· 使用关键字 abstract 修饰的类称为抽象类。
· 可以包含抽象方法(使用 abstract 修饰,没有方法体)和具体方法(有方法体)。
· 语法示例:
```java
public abstract class Animal {
protected String name;
public Animal(String name) {
this.name = name;
}
// 抽象方法
public abstract void makeSound();
// 具体方法
public void sleep() {
System.out.println(name + " is sleeping");
}
}
```
2. 抽象类的核心特点
· 不能实例化:不能通过 new 关键字创建抽象类的对象,只能通过子类实例化。
· 可以包含构造器:虽然不能实例化,但可以有构造器,用于给子类构造器调用(初始化父类成员)。
· 可以包含成员变量:与普通类一样,可以定义各种访问权限的成员变量。
· 可以包含具体方法:既可以有抽象方法,也可以有已实现的方法。
· 可以包含 main 方法:抽象类中也可以定义 main 方法,可以运行(但通常不这么做)。
· 可以继承其他类或实现接口:抽象类可以继承一个普通类或另一个抽象类,也可以实现多个接口。
3. 抽象方法
· 使用 abstract 修饰,没有方法体,以分号结束。
· 必须被子类实现:非抽象子类必须重写所有抽象方法;抽象子类可以选择实现部分或全部抽象方法,也可以继续声明抽象方法。
· 抽象方法不能是 private、static、final、synchronized:
· private:子类不可见,无法重写。
· static:属于类级别,不能被覆盖。
· final:禁止重写。
· synchronized:与方法体相关,抽象方法无方法体,无意义。
4. 抽象类的继承
· 当子类继承抽象类时:
· 如果子类是非抽象类,则必须实现父类中所有的抽象方法。
· 如果子类也是抽象类,则可以选择实现部分抽象方法,也可以完全不实现,继续将未实现的方法作为抽象方法传递给下一级子类。
· 子类可以重写父类的具体方法,也可以添加新的抽象方法。
5. 抽象类与普通类的区别
特性 抽象类 普通类
实例化 不能 new 可以 new
抽象方法 可以包含(0个或多个) 不能包含
继承 必须被继承才有意义 可以被继承也可不被继承
构造器 可以有 可以有
成员变量 可以有 可以有
具体方法 可以有 可以有
final 修饰 不能是 final(否则无法继承) 可以是 final
6. 抽象类与接口的对比(Java 8+)
随着Java版本升级,接口不断增强,两者的界限变得模糊,但仍有本质区别:
比较维度 抽象类 接口(Interface)
关键字 abstract class interface
继承/实现 单继承(只能继承一个抽象类) 多实现(一个类可实现多个接口)
构造器 可以有 不能有(接口没有构造器)
成员变量 可以是各种类型,可以有非静态、非 final 变量 默认是 public static final 常量(Java 9+支持私有变量,但仍是静态常量)
方法 可以有抽象方法、具体方法、静态方法 Java 8前:只能有抽象方法;Java 8+:可以有 default 和 static 方法;Java 9+:可以有 private 方法
访问修饰符 可以使用所有访问权限 默认 public,Java 9+支持 private 方法
设计思想 代码复用,模板模式,定义“是什么” 契约规范,行为约定,定义“能做什么”
初始化顺序 先执行父类构造器,再初始化子类成员 接口没有构造器,不存在初始化顺序问题
典型使用场景:
· 抽象类:当多个类有公共代码需要复用,且需要定义模板方法时(例如模板方法模式)。
· 接口:定义行为规范,实现多态解耦,例如各种回调接口、策略模式。
7. 抽象类的设计意义与常见应用
· 代码复用:将子类共有的属性和方法提取到抽象类中,避免重复代码。
· 定义模板:模板方法模式(Template Method)中,抽象类定义算法的骨架(具体方法),将一些步骤延迟到子类实现(抽象方法)。
```java
public abstract class Game {
public final void play() { // 模板方法
initialize();
startPlay();
endPlay();
}
abstract void initialize();
abstract void startPlay();
abstract void endPlay();
}
```
· 强制子类行为:通过抽象方法强制子类提供特定实现,保证一定的规范性。
· 作为中间层:在框架设计中,常用抽象类作为基础类,提供默认实现,同时留出扩展点。
8. 使用抽象类的注意事项
· 抽象类可以没有抽象方法,但即使没有抽象方法,它仍然不能实例化(常用于禁止直接实例化的工具类,但这种情况更多用 final 类配合私有构造器)。
· 构造器的调用:抽象类的构造器在子类实例化时被调用,用于初始化父类成员。
· 与 final 冲突:抽象类不能同时被 final 修饰(因为 final 类不可继承,而抽象类必须被继承)。
· 访问权限:抽象方法的访问权限不能是 private,否则子类无法实现。
· 异常抛出:抽象方法可以声明抛出异常,子类实现时抛出的异常必须是父类异常的子集或相同。
9. 常见面试题
· 抽象类和接口如何选择?
需要代码复用、定义共同状态(成员变量)时用抽象类;需要多实现、定义能力契约时用接口。
· 抽象类中能否有 main 方法?
可以,抽象类可以包含 main 方法,可以运行(但实例化仍需通过子类)。
· 为什么抽象类不能实例化?
因为抽象类可能包含未实现的抽象方法,如果允许实例化,调用抽象方法会导致无法执行。
· 抽象方法是否可以定义在非抽象类中?
不可以,只有抽象类才能包含抽象方法。
· 一个类继承抽象类,但没有实现所有抽象方法,怎么办?
该类必须声明为抽象类。
