1.1抽象类概念
在⾯向对象的概念中,所有的对象都是通过类来描绘的,但是反过来,并不是所有的类都是⽤来描绘对象的,如果⼀个类中没有包含⾜够的信息来描绘⼀个具体的对象,这样的类就是抽象类。
1.2定义抽象类是一种特殊的类,它不能被实例化(即不能创建对象)。它通常作为其他类的基类(父类)而存在,用于定义一组公共的接口和部分实现,强制要求其派生类(子类)必须遵循某种结构或实现某些特定方法。在面向对象编程(OOP)中,抽象类是实现抽象化和多态性的关键工具之一。
1.3抽象类的语法在Java中,⼀个类如果被 abstract 修饰称为抽象类,抽象类中被方法,抽象方法不⽤给出具体的实现体。
代码语言:javascript复制 // 抽象类:被abstract修饰的类
public abstract class Shape {
// 抽象⽅法:被abstract修饰的⽅法,没有⽅法体
abstract public void draw();
abstract void calcArea();
// 抽象类也是类,也可以增加普通⽅法和属性
public double getArea(){
return area;
}
}
// abstract 修饰的⽅法称为抽象方法
protected double area;
// ⾯积注:抽象类也是类,内部可以包含普通⽅法和属性,甚⾄构造⽅法
1.4抽象类的特性不能被实例化代码语言:javascript复制//这里假设这个抽象类类名为Animals
Animasl animal = new Animals();
//编译错误
//抽象类无法实例化这是抽象类最根本的特性。你不能使用 new 关键字来创建一个抽象类的对象。它的存在意义是“被继承”。
为什么? 因为它本身可能包含未实现的抽象方法,这些方法没有具体的函数体。创建一个不完整的对象是没有意义的,也是不允许的。
可以包含抽象方法
抽象方法是一种只有声明(方法签名)而没有实现(没有方法体)的方法。它使用 abstract 关键字进行修饰。代码语言:javascript复制 // 1. 抽象方法 (必须用 abstract,无方法体)
abstract void abstractMethod();作用:抽象方法在抽象类中定义了一个“契约”或“规范”,强制任何继承它的非抽象子类必须提供该方法的具体实现。这确保了所有子类都拥有某种特定的行为。
也可以包含普通方法
抽象类并非只能有抽象方法。它可以和普通类一样,拥有已经实现了的成员方法、属性、字段、构造函数等。代码语言:javascript复制 // 2. 普通的具体方法 (有方法体,子类可直接继承或重写)
void concreteMethod() {
System.out.println("我是一个已经实现的方法");
}好处:这允许你在抽象类中提供一些通用的功能实现,子类可以直接继承或重写这些方法,避免了代码重复,实现了代码复用。
这个是防止大家混淆,举了几个方法的例子
代码语言:javascript复制abstract class Example {
// 1. 抽象方法 (必须用 abstract,无方法体)
abstract void abstractMethod();
// 2. 普通的具体方法 (有方法体,子类可直接继承或重写)
void concreteMethod() {
System.out.println("我是一个已经实现的方法");
}
// 3. 静态方法 (属于类本身,有方法体)
static void staticMethod() {
System.out.println("我是一个静态方法");
}
// 4. 私有方法 (Java 9+,有方法体,通常用于辅助内部逻辑)
private void privateMethod() {
System.out.println("内部使用的私有方法");
}
}构造函数
抽象类虽然不能实例化,但可以拥有构造函数。这个构造函数在其子类被实例化时会被调用(通常通过 super() 在子类构造函数中调用),用于初始化抽象类中定义的字段或执行一些公共的初始化逻辑。比如下面就是一个抽象类,写的结构比较完善,让大家更好的理解抽象类。代码语言:javascript复制abstract class Employee {
// 所有员工都有的共同字段(由抽象类的构造函数初始化)
private String name;
private int id;
private double baseSalary; // 基本工资
// 抽象类的构造函数 - 用于初始化公共字段
public Employee(String name, int id, double baseSalary) {
this.name = name;
this.id = id;
this.baseSalary = baseSalary;
System.out.println("员工基本信息已初始化: " + name + " (ID: " + id + ")");
}
// 抽象方法:计算最终工资(不同岗位算法不同)
public abstract double calculateSalary();
// 普通方法:获取基本信息(所有子类都可使用)
public void displayBasicInfo() {
System.out.println("姓名: " + name + ", 工号: " + id + ", 基本工资: " + baseSalary);
}
// 获取基本工资(可能在计算最终工资时用到)
protected double getBaseSalary() {
return baseSalary;
}
}
// 具体子类:开发人员
class Developer extends Employee {
private double bonus; // 开发人员特有的奖金字段
// 子类构造函数
public Developer(String name, int id, double baseSalary, double bonus) {
// 调用父类构造函数初始化公共字段(name, id, baseSalary)
super(name, id, baseSalary);
this.bonus = bonus;
System.out.println("开发人员特有信息已初始化,奖金: " + bonus);
}
// 实现抽象方法:开发人员的工资计算方式
@Override
public double calculateSalary() {
return getBaseSalary() + bonus; // 基本工资 + 奖金
}
// 开发人员特有的方法
public void code() {
System.out.println("开发人员正在编码...");
}
}
// 具体子类:经理
class Manager extends Employee {
private double allowance; // 经理特有的津贴字段
// 子类构造函数
public Manager(String name, int id, double baseSalary, double allowance) {
// 调用父类构造函数初始化公共字段
super(name, id, baseSalary);
this.allowance = allowance;
System.out.println("经理特有信息已初始化,津贴: " + allowance);
}
// 实现抽象方法:经理的工资计算方式
@Override
public double calculateSalary() {
return getBaseSalary() + allowance; // 基本工资 + 津贴
}
// 经理特有的方法
public void manage() {
System.out.println("经理正在管理团队...");
}
}
// 测试类
public class CompanySystem {
public static void main(String[] args) {
System.out.println("=== 创建开发人员对象 ===");
Developer dev = new Developer("张三", 1001, 15000.0, 5000.0);
dev.displayBasicInfo();
System.out.println("最终工资: " + dev.calculateSalary());
dev.code();
System.out.println("\n=== 创建经理对象 ===");
Manager manager = new Manager("李四", 2001, 20000.0, 10000.0);
manager.displayBasicInfo();
System.out.println("最终工资: " + manager.calculateSalary());
manager.manage();
}
}继承
子类使用 extends 关键字来继承一个抽象类。如果一个子类也是抽象类,它可以不实现父抽象类的所有抽象方法。
如果一个子类是普通(具体)类,则必须实现(Override)其父抽象类中所有的抽象方法,否则编译器会报错。
抽象类必须被继承,并且继承后⼦类要重写⽗类中的抽象⽅法,否则⼦类也是抽象类,必须要使⽤abstract
修饰
6.不能被static,final,private修饰,因为抽象方法要被子类重写。
代码语言:javascript复制abstract class Example {
// 1. 抽象方法 (必须用 abstract,无方法体)
abstract void abstractMethod();
// 2. 普通的具体方法 (有方法体,子类可直接继承或重写)
void concreteMethod() {
System.out.println("我是一个已经实现的方法");
}
// 3. 静态方法 (属于类本身,有方法体)
static void staticMethod() {
System.out.println("我是一个静态方法");
}
// 4. 私有方法 (Java 9+,有方法体,通常用于辅助内部逻辑)
private void privateMethod() {
System.out.println("内部使用的私有方法");
}
}注意:
抽象类中不⼀定包含抽象⽅法,但是有抽象⽅法的类⼀定是抽象类。抽象类中可以有构造⽅法,供⼦类创建对象时,初始化⽗类的成员变量。1.5抽象类的作用代码语言:javascript复制 抽象类的五大核心作用
1. 代码复用 (Code Reuse)作用:将多个相关类共有的属性和行为提取到抽象类中,子类可以直接继承使用,避免代码重复。
代码语言:javascript复制abstract class Vehicle {
private String brand;
private int maxSpeed;
// 公共方法,所有子类都可使用
public void startEngine() {
System.out.println("引擎启动中...");
}
public void stopEngine() {
System.out.println("引擎关闭中...");
}
}
class Car extends Vehicle {
// Car 自动拥有了 startEngine() 和 stopEngine() 方法
}
class Motorcycle extends Vehicle {
// Motorcycle 也自动拥有了这些方法
}强制规范与定义契约 (Enforcing Contracts)
作用:通过抽象方法,强制要求所有非抽象子类必须实现特定的方法,确保系统架构的一致性。代码语言:javascript复制abstract class DatabaseConnector {
// 强制子类必须实现连接方法
public abstract void connect();
public abstract void disconnect();
public abstract void executeQuery(String query);
}
class MySQLConnector extends DatabaseConnector {
@Override
public void connect() { System.out.println("连接MySQL数据库..."); }
@Override
public void disconnect() { System.out.println("断开MySQL连接..."); }
@Override
public void executeQuery(String query) { System.out.println("执行MySQL查询: " + query); }
}
// 任何新的数据库连接器都必须实现这三个方法实现多态 (Polymorphism)
作用:允许使用抽象类类型作为引用,在运行时动态指向不同的具体子类对象,实现同一接口的不同行为。代码语言:javascript复制abstract class Shape {
public abstract double calculateArea();
}
class Circle extends Shape {
private double radius;
public double calculateArea() { return Math.PI * radius * radius; }
}
class Rectangle extends Shape {
private double width, height;
public double calculateArea() { return width * height; }
}
// 使用多态
public class Test {
public static void main(String[] args) {
Shape shape1 = new Circle(5.0); // 指向Circle对象
Shape shape2 = new Rectangle(4.0, 6.0); // 指向Rectangle对象
System.out.println("圆形面积: " + shape1.calculateArea()); // 调用Circle的实现
System.out.println("矩形面积: " + shape2.calculateArea()); // 调用Rectangle的实现
}
}提供部分实现 (Partial Implementation)
作用:抽象类可以提供一些已经实现的方法,同时留下一些抽象方法让子类去完成,实现"模板方法"设计模式。代码语言:javascript复制abstract class Game {
// 已经实现的方法
public void initialize() {
System.out.println("游戏初始化完成");
}
public void start() {
initialize();
play(); // 调用抽象方法
end();
}
public void end() {
System.out.println("游戏结束");
}
// 抽象方法,子类必须实现具体的游戏逻辑
public abstract void play();
}
class Chess extends Game {
@Override
public void play() {
System.out.println("下国际象棋中...");
}
}
class Poker extends Game {
@Override
public void play() {
System.out.println("玩扑克牌中...");
}
}提高可维护性和扩展性 (Maintainability and Extensibility)
作用:当需要添加新功能时,只需创建新的子类继承抽象类并实现抽象方法即可,无需修改现有代码,符合"开闭原则"。代码语言:javascript复制// 现有系统
abstract class PaymentProcessor {
public abstract boolean processPayment(double amount);
}
class CreditCardProcessor extends PaymentProcessor {
public boolean processPayment(double amount) { /* 信用卡处理逻辑 */ }
}
class PayPalProcessor extends PaymentProcessor {
public boolean processPayment(double amount) { /* PayPal处理逻辑 */ }
}
// 未来扩展:添加新的支付方式无需修改现有代码
class CryptoProcessor extends PaymentProcessor {
public boolean processPayment(double amount) { /* 加密货币处理逻辑 */ }
}抽象类本⾝不能被实例化,要想使用,只能创建该抽象类的⼦类.然后让子类重写抽象类中的抽象方法.抽象类相当于多了⼀重编译器的校验.那使用场景是什么呢,使用抽象类的场景在实际工作不应该由父类完成,而应由子类完成.那么此时如果不小心误用成父类了,使用普通类编译器是不会报错的.但是父类是抽象类就会在实例化的时候提示错误,让我们尽早发现问题.