112. Java 继承 - 抽象方法和类

112. Java 继承 - 抽象方法和类

抽象方法和类

抽象类 是一个声明为 abstract 的类,它不能被直接实例化。抽象类可能包含抽象方法,也可以没有抽象方法。抽象方法是没有具体实现的方法,它仅仅声明了方法的签名,而没有提供方法的实际代码实现。抽象类的作用是为子类提供一个模板,让子类根据自己的需要来实现这些抽象方法。

抽象方法

抽象方法的声明方式如下:

java 复制代码
abstract void moveTo(double deltaX, double deltaY);

在上面的例子中,moveTo 是一个抽象方法,它没有方法体。它仅定义了方法的签名,而没有提供实现。任何继承此抽象类的子类都必须实现该方法,除非子类本身也是抽象类。

抽象类

如果一个类中包含抽象方法,那么该类也必须声明为 abstract,如下所示:

java 复制代码
public abstract class GraphicObject {
    // 声明字段
    // 声明非抽象方法
    abstract void draw();
}

在这个例子中,GraphicObject 是一个抽象类,它包含一个抽象方法 draw(),要求所有继承该类的子类必须实现 draw() 方法。

注意 :接口中的方法默认都是抽象的,除非明确声明为 defaultstatic。因此,接口方法不需要显式地使用 abstract 关键字。

抽象类与接口的比较

抽象类和接口有许多相似之处,都是用于描述类的行为和结构,但它们有显著的不同之处。

抽象类

  • 不能实例化:不能创建抽象类的实例。
  • 可以包含字段 :可以包含字段,包括非 static 和非 final 字段。
  • 可以包含方法 :可以包含具体实现的非 static 和非 final 方法。
  • 继承限制:一个类只能继承一个抽象类。

接口

  • 可以多继承:一个类可以实现多个接口。
  • 方法默认是 abstract :接口中的方法默认是抽象的,除非声明为 defaultstatic
  • 字段 :接口中的字段默认是 public static final

何时使用抽象类,何时使用接口?

  • 使用抽象类 :如果希望在多个相关的类之间共享代码,或者类需要多个常用的字段或方法,或者需要使用 protectedprivate 等访问修饰符,那么应使用抽象类。
  • 使用接口 :如果期望不同的类实现相同的行为,但这些类没有任何继承关系(例如,ComparableCloneable 接口),或者希望支持多重继承时,应使用接口。

示例:

JDK 中的 AbstractMap 类就是一个抽象类,包含了许多可以共享的操作(如 get(), put() 方法)。具体实现如 HashMapTreeMap 继承了该类并提供了具体实现。

另一方面,HashMap 类实现了多个接口,如 SerializableCloneableMap<K, V>。这意味着 HashMap 的实例不仅是一个映射结构,还具备克隆和序列化的能力。

抽象类示例

假设我们正在开发一个面向对象的绘图应用程序,需要绘制不同的图形对象,如圆形、矩形、线条等。这些图形对象有一些共同的状态(如位置、颜色)和行为(如移动、旋转、调整大小、绘制)。但是,每种图形对象的绘制和调整大小方式可能不同。

定义抽象类

java 复制代码
abstract class GraphicObject {
    int x, y;  // 图形的坐标
    String color;  // 图形的颜色
    
    // 共享的行为
    void moveTo(int newX, int newY) {
        x = newX;
        y = newY;
    }

    // 需要子类实现的行为
    abstract void draw();
    abstract void resize();
}

在上面的例子中,GraphicObject 是一个抽象类,包含了所有图形对象共有的状态(如 x, y, color)和方法(如 moveTo)。但是,drawresize 方法是抽象的,因为每种图形对象的绘制和调整大小方式不同,需要在子类中实现。

子类实现抽象方法

java 复制代码
class Circle extends GraphicObject {
    void draw() {
        System.out.println("Drawing a Circle at (" + x + ", " + y + ")");
    }

    void resize() {
        System.out.println("Resizing the Circle.");
    }
}

class Rectangle extends GraphicObject {
    void draw() {
        System.out.println("Drawing a Rectangle at (" + x + ", " + y + ")");
    }

    void resize() {
        System.out.println("Resizing the Rectangle.");
    }
}

在上面的代码中,CircleRectangleGraphicObject 的子类,它们实现了 draw()resize() 方法。每个子类根据其图形的不同特点提供了具体的实现。

当抽象类实现接口时

一个抽象类可以实现一个接口,但不需要实现接口中的所有方法。子类可以继承抽象类并实现接口中剩余的未实现方法。

例如:

java 复制代码
abstract class X implements Y {
    // 实现接口 Y 中的部分方法
}

class XX extends X {
    // 完成实现接口 Y 中剩余的方法
}

在这个例子中,类 X 实现了接口 Y,但是它没有实现接口中的所有方法,因此 X 被声明为抽象类。类 XX 继承了 X 并实现了接口 Y 中剩余的方法。

抽象类的静态成员

虽然抽象类不能被实例化,但它仍然可以拥有静态字段和静态方法。您可以像普通类一样使用静态方法,例如:

java 复制代码
abstract class AbstractClass {
    static void staticMethod() {
        System.out.println("Static method in abstract class");
    }
}

public class TestClass {
    public static void main(String[] args) {
        AbstractClass.staticMethod();  // 直接通过类名调用静态方法
    }
}

静态方法和字段是类级别的,而不是实例级别的,因此您不需要实例化类就可以访问它们。


通过这些示例和扩展,抽象类和方法的概念应该更加清晰了。抽象类是面向对象编程中非常重要的一部分,它帮助我们建立类之间的共性,并在不同的子类中实现多态性。

相关推荐
一 乐6 小时前
婚纱摄影网站|基于ssm + vue婚纱摄影网站系统(源码+数据库+文档)
前端·javascript·数据库·vue.js·spring boot·后端
C_心欲无痕6 小时前
ts - tsconfig.json配置讲解
linux·前端·ubuntu·typescript·json
清沫6 小时前
Claude Skills:Agent 能力扩展的新范式
前端·ai编程
码事漫谈7 小时前
Protocol Buffers 编码原理深度解析
后端
码事漫谈7 小时前
gRPC源码剖析:高性能RPC的实现原理与工程实践
后端
yinuo7 小时前
前端跨页面通信终极指南:方案拆解、对比分析
前端
yinuo7 小时前
前端跨页面通讯终极指南⑨:IndexedDB 用法全解析
前端
xkxnq8 小时前
第二阶段:Vue 组件化开发(第 16天)
前端·javascript·vue.js
烛阴8 小时前
拒绝配置地狱!5 分钟搭建 Three.js + Parcel 完美开发环境
前端·webgl·three.js
xkxnq8 小时前
第一阶段:Vue 基础入门(第 15天)
前端·javascript·vue.js