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

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


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

相关推荐
teeeeeeemo3 分钟前
Number.toFixed() 与 Math.round() 深度对比解析
开发语言·前端·javascript·笔记
why1517 分钟前
6.15 操作系统面试题 锁 内存管理
后端·性能优化
阿珊和她的猫24 分钟前
`toRaw` 与 `markRaw`:Vue3 响应式系统的细粒度控制
前端·javascript·vue.js·typescript
网络点点滴26 分钟前
探索 Vue 替代方案
前端·javascript·vue.js
丘山子32 分钟前
如何确保 Go 系统在面临超时或客户端主动取消时,能够优雅地释放资源?
后端·面试·go
武子康35 分钟前
Java-52 深入浅出 Tomcat SSL工作原理 性能优化 参数配置 JVM优化
java·jvm·后端·servlet·性能优化·tomcat·ssl
OnlyLowG1 小时前
SpringSecurity导致redis压力大问题解决
后端
深栈解码1 小时前
OpenIM 源码深度解析系列(十四):事件增量同步机制解析
后端
想用offer打牌1 小时前
一站式了解CDN😈
后端·架构·cdn
江城开朗的豌豆1 小时前
Vue的keep-alive缓存揭秘:多出来的生命周期怎么玩?
前端·javascript·vue.js