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();  // 直接通过类名调用静态方法
    }
}

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


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

相关推荐
涡能增压发动积21 小时前
同样的代码循环 10次正常 循环 100次就抛异常?自定义 Comparator 的 bug 让我丢尽颜面
后端
Wenweno0o21 小时前
0基础Go语言Eino框架智能体实战-chatModel
开发语言·后端·golang
于慨21 小时前
Lambda 表达式、方法引用(Method Reference)语法
java·前端·servlet
石小石Orz21 小时前
油猴脚本实现生产环境加载本地qiankun子应用
前端·架构
swg32132121 小时前
Spring Boot 3.X Oauth2 认证服务与资源服务
java·spring boot·后端
从前慢丶21 小时前
前端交互规范(Web 端)
前端
tyung1 天前
一个 main.go 搞定协作白板:你画一笔,全世界都看见
后端·go
gelald1 天前
SpringBoot - 自动配置原理
java·spring boot·后端
CHU7290351 天前
便捷约玩,沉浸推理:线上剧本杀APP功能版块设计详解
前端·小程序
GISer_Jing1 天前
Page-agent MCP结构
前端·人工智能