Java 抽象
Java - 抽象
Section titled “Java - 抽象”抽象(Abstraction)是面向对象编程(Object-Oriented Programming, OOP)的核心概念之一。它侧重于隐藏复杂的实现细节,只暴露对象或系统的基本特征或功能。
想象一下驾驶汽车:你只需要与方向盘、油门、刹车等基本控制装置交互(抽象),而无需了解发动机内部燃烧或刹车系统液压等复杂的实现细节(implementation details)。
在 Java 中,抽象主要通过以下方式实现:
- 抽象类(Abstract Classes): 不能被实例化,并且可能包含抽象方法(abstract methods)的类。
- 接口(Interfaces): 定义抽象方法(以及可能的默认方法/静态方法)契约的引用类型。
本章重点介绍抽象类。
抽象类是其他类的模板或蓝图。它使用 abstract 关键字声明。
抽象类的主要特性:
Section titled “抽象类的主要特性:”- 不能被实例化(Cannot be Instantiated): 你不能使用
new关键字直接创建抽象类的对象。 - 可以包含抽象方法(Can Have Abstract Methods): 使用
abstract关键字声明且没有具体实现(没有方法体,以分号结束)的方法。如果一个类包含至少一个抽象方法,则该类必须被声明为抽象类。 - 可以包含具体方法(Can Have Concrete Methods): 可以包含带有实现的普通方法。
- 可以包含构造方法(Can Have Constructors): 抽象类可以包含构造方法,当创建具体子类的实例时会调用这些构造方法(通常通过子类构造方法中的
super()调用)。 - 可以包含字段(Can Have Fields): 可以包含实例变量(状态)和静态变量。
- 可以被继承(Subclassing): 旨在被继承(使用
extends关键字)。具体(非抽象)子类必须为其继承的所有抽象方法提供实现。
为什么使用抽象类?
Section titled “为什么使用抽象类?”- 代码复用(Code Reusability): 提供子类可以继承的通用字段和方法实现。
- 强制结构(Enforce Structure): 定义所有子类必须实现的通用结构和必需方法(抽象方法),确保一致性。
- 模板设计(Template Design): 作为相关类的基础,定义一个过于抽象而不能独立存在的通用概念或实体,但为特定类型提供了基础。
- 多态(Polymorphism): 允许通过抽象类类型的引用来处理不同子类的对象。
在 class 关键字之前使用 abstract 关键字。
示例:抽象类 Shape
Section titled “示例:抽象类 Shape”/* 文件名:Shape.java */
public abstract class Shape { private String color;
// Constructor (called by subclasses) public Shape(String color) { System.out.println("Shape constructor called for color: " + color); this.color = color; }
// Concrete method (shared implementation) public String getColor() { return color; }
public void setColor(String color) { this.color = color; }
// Abstract method (must be implemented by concrete subclasses) public abstract double calculateArea();
// Another abstract method public abstract void draw();}尝试实例化抽象类会导致编译时错误:
// 这会导致编译错误:// Shape myShape = new Shape("Red"); // 错误:Shape 是抽象的;不能被实例化具体类使用 extends 关键字继承抽象类。它必须为其从抽象父类继承的所有抽象方法提供实现。使用 @Override 注解可以提高清晰度并进行编译器检查。
示例:具体子类 Circle
Section titled “示例:具体子类 Circle”public class Circle extends Shape { // 继承抽象类 Shape private double radius;
public Circle(String color, double radius) { super(color); // 调用抽象父类的构造方法 System.out.println("Circle constructor called."); this.radius = radius; }
public double getRadius() { return radius; }
// 实现 Shape 中的抽象方法 @Override public double calculateArea() { return Math.PI * radius * radius; }
// 实现 Shape 中的另一个抽象方法 @Override public void draw() { System.out.println("Drawing a " + getColor() + " circle with radius " + radius); }}示例:具体子类 Rectangle
Section titled “示例:具体子类 Rectangle”public class Rectangle extends Shape { private double width; private double height;
public Rectangle(String color, double width, double height) { super(color); System.out.println("Rectangle constructor called."); this.width = width; this.height = height; }
@Override public double calculateArea() { return width * height; }
@Override public void draw() { System.out.println("Drawing a " + getColor() + " rectangle with width " + width + " and height " + height); }}使用抽象类和子类(多态)
Section titled “使用抽象类和子类(多态)”你可以创建具体子类的对象,并使用多态性通过抽象类类型引用它们。
/* 文件名:AbstractionDemo.java */
public class AbstractionDemo { public static void main(String[] args) { // 不能创建 Shape 对象:Shape s1 = new Shape("Blue"); // 错误!
// 创建具体子类的对象 Shape circle = new Circle("Red", 5.0); Shape rectangle = new Rectangle("Blue", 4.0, 6.0);
System.out.println("\n--- Circle Info ---"); System.out.println("Color: " + circle.getColor()); // 继承的具体方法 System.out.println("Area: " + circle.calculateArea()); // 重写的抽象方法 circle.draw(); // 重写的抽象方法 // 错误:getRadius() 不在 Shape 中。需要强制类型转换: if (circle instanceof Circle) { Circle c = (Circle) circle; System.out.println("Radius: " + c.getRadius()); }
System.out.println("\n--- Rectangle Info ---"); System.out.println("Color: " + rectangle.getColor()); System.out.println("Area: " + rectangle.calculateArea()); rectangle.draw();
System.out.println("\n--- 数组与多态 ---"); Shape[] shapes = { circle, rectangle, new Circle("Green", 2.5) };
for (Shape currentShape : shapes) { currentShape.draw(); // 调用 Circle 或 Rectangle 特定的 draw() 方法 System.out.println("Area: " + currentShape.calculateArea()); System.out.println("--"); } }}预期输出(示意):
Shape constructor called for color: RedCircle constructor called.Shape constructor called for color: BlueRectangle constructor called.
--- Circle Info ---Color: RedArea: 78.53981633974483Drawing a Red circle with radius 5.0Radius: 5.0
--- Rectangle Info ---Color: BlueArea: 24.0Drawing a Blue rectangle with width 4.0 and height 6.0
--- Polymorphism with Array ---Shape constructor called for color: GreenCircle constructor called.Drawing a Red circle with radius 5.0Area: 78.53981633974483--Drawing a Blue rectangle with width 4.0 and height 6.0Area: 24.0--Drawing a Green circle with radius 2.5Area: 19.634954084936208--抽象类 vs. 接口
Section titled “抽象类 vs. 接口”抽象类和接口都用于实现抽象,但它们之间有关键区别:
- 继承: 一个类只能继承(extend)一个抽象类,但可以实现(implement)多个接口。
- 字段: 抽象类可以有实例变量(状态)。接口主要包含
public static final常量(虽然技术上可以使用默认方法模拟状态,但这并非其预期用途)。 - 方法: 抽象类可以包含抽象方法和具体方法。接口包含抽象方法,并且自 Java 8 起,也可以包含默认方法(已实现)和静态方法。
- 构造方法: 抽象类可以有构造方法;接口不能有。
- 用途: 对于子类共享通用状态和实现的“is-a”关系,使用抽象类。对于“has-a”或“can-do”关系,使用接口来定义一个可能不相关的类可以实现的某种能力或契约。