抽象类是“半成品”?普通类是“成品”?看完你就懂了!

285 阅读4分钟

在 Java 中,普通类抽象类 是定义类的两种常见方式,它们的区别在于使用场景和功能。


1. 什么是普通类?

普通类是 Java 中最常见的类,它可以直接用来创建对象,并且类中的方法需要有完整的实现。

特性:

  • 可以直接实例化(创建对象)。
  • 类中的方法必须有完整的实现(即不能有未实现的方法)。
  • 适合用来编写具体的功能实现。

通俗类比:

普通类就像一个普通的工厂,既有明确的生产方法,又能直接开门营业,制造和提供具体的产品。

代码示例:

class Animal {
    // 普通方法,有完整的实现
    void makeSound() {
        System.out.println("Animal makes a sound");
    }
}

public class Main {
    public static void main(String[] args) {
        // 创建普通类的对象
        Animal animal = new Animal();
        animal.makeSound(); // 输出:Animal makes a sound
    }
}

2. 什么是抽象类?

抽象类是一个不能直接实例化的特殊类,用来作为其他类的“模板”“基类”。它可以包含未实现的方法(抽象方法),具体的实现由子类提供。

特性:

  • 不能直接实例化(不能创建对象)。
  • 可以包含抽象方法(没有方法体的方法,只有声明),也可以包含普通方法(有方法体)。
  • 必须通过继承,使子类提供抽象方法的具体实现。

通俗类比:

抽象类就像一个“设计蓝图”“半成品工厂”,它定义了产品的基本框架,具体的生产过程需要由子工厂(子类)来实现。

示例:

// 定义抽象类
abstract class Animal {
    // 抽象方法,没有方法体,子类必须实现
    abstract void makeSound();

    // 普通方法,有完整的实现
    void eat() {
        System.out.println("Animal eats food");
    }
}

// 子类继承抽象类并实现抽象方法
class Dog extends Animal {
    @Override
    void makeSound() {
        System.out.println("Dog barks");
    }
}

public class Main {
    public static void main(String[] args) {
        // Animal animal = new Animal(); // 错误!抽象类不能直接实例化

        // 创建子类对象
        Dog dog = new Dog();
        dog.makeSound(); // 输出:Dog barks
        dog.eat();       // 输出:Animal eats food
    }
}

3. 抽象类和普通类的核心区别

特性普通类抽象类
是否可以实例化可以直接创建对象不能直接创建对象
是否包含抽象方法不能包含抽象方法可以包含抽象方法(也可以没有)
目标用于实现具体功能用作模板,定义通用结构,供子类扩展
使用场景当类的功能是独立且完整时使用当类需要作为通用模板,定义规则时使用

4. 使用场景对比:什么时候用普通类,什么时候用抽象类?

普通类:

  • 当类的功能是独立且完整的。
  • 适合实现具体的功能逻辑。
  • 不需要继承或者扩展。

例如:

class Calculator {
    int add(int a, int b) {
        return a + b;
    }
}

抽象类:

  • 当类需要作为其他类的基础模板
  • 用于定义通用的规则或方法,让子类完成具体的实现。
  • 适合在多个子类中共享部分逻辑,同时允许子类提供个性化实现。

例如:

abstract class Shape {
    // 抽象方法,定义规则
    abstract double calculateArea();

    // 普通方法,提供通用功能
    void display() {
        System.out.println("This is a shape");
    }
}

class Circle extends Shape {
    double radius;

    Circle(double radius) {
        this.radius = radius;
    }

    @Override
    double calculateArea() {
        return Math.PI * radius * radius; // 圆的面积公式
    }
}

class Rectangle extends Shape {
    double length, width;

    Rectangle(double length, double width) {
        this.length = length;
        this.width = width;
    }

    @Override
    double calculateArea() {
        return length * width; // 矩形的面积公式
    }
}

使用场景:

  • Shape 是一个模板,它定义了共有的特性(如 display 方法),并要求子类提供具体的 calculateArea 实现。
  • CircleRectangle 是具体的形状类,它们继承模板类并实现其抽象方法。

5. 抽象类 vs 接口(补充)

有时候抽象类和接口容易混淆,这里简单提一下它们的区别:

  • 抽象类 可以有抽象方法和普通方法(有方法体),还可以有成员变量。
  • 接口 只能定义抽象方法(Java 8 之后允许有默认方法和静态方法),不能包含实例变量。

总结

  • 普通类 是“完整的房子”,可以直接住(实例化)。
  • 抽象类 是“设计图纸”,需要子类(具体房子)来完成剩下的部分,才能使用。