学习Java41天

抽象类 (Abstract Class)

一、抽象类的基本概念

1. 抽象方法
  • 定义 :一个没有方法体的方法(即只有方法声明,没有具体的实现)。

  • 格式

    java

    复制代码
    public abstract 返回值类型 方法名(参数列表);
  • 特点

    • 使用 abstract 关键字修饰。

    • 没有方法体,直接以分号 ; 结束。

    • 它定义了一个 "必须实现"的规范或契约

2. 抽象类
  • 定义 :包含抽象方法的类必须被声明为抽象类。

  • 格式

    java

    复制代码
    public abstract class 类名 {
        // 类的内容
    }
  • 特点

    • 使用 abstract 关键字修饰类。

    • 抽象类不能直接实例化 (不能 new 抽象类)。

二、抽象类的作用与设计思想

抽象类的核心是一种 "未完成"的类设计模板

  1. 抽取共性,定义规范

    • 当在父类中提取多个子类的共性行为时,如果无法(或不适合)确定该行为的具体实现 ,就将该方法声明为抽象方法

    • 这样,抽象类就定义了一个 "规范"或"契约" ,强制所有非抽象的子类必须按照这个声明来提供具体的实现。

  2. 强制子类重写

    • 子类继承抽象类后,必须处理这些抽象方法。这保证了代码的一致性。

通俗理解 :抽象类就像是制定了一份 "必须完成的任务清单"。清单上只写了任务名称和要求(抽象方法),但没写怎么做。子类就像不同的执行者,它们必须按照清单完成所有任务(实现所有抽象方法),但可以根据自己的情况选择不同的完成方式。

三、继承抽象类的注意事项

当一个普通类继承一个抽象类时,有两种选择:

  1. 重写所有抽象方法(推荐,也是最常见的情况)

    • 将父类中定义的所有抽象方法都提供具体的实现。

    • 这样,子类就成为了一个 "具体类",可以被正常实例化。

  2. 将自己也声明为抽象类

    • 如果子类没有重写没有重写全部 的抽象方法,那么这个子类也必须abstract 关键字修饰,成为一个新的抽象类。

    • 这个新的抽象类可以继续被其他类继承。

简单总结"抽象"具有传递性。一个类只要继承了抽象方法而没有实现它,它自己就必须保持抽象。

四、抽象类的其他特性

  1. 抽象类中可以有构造方法

    • 虽然抽象类不能直接实例化,但它可以有构造方法

    • 构造方法用于子类创建对象时,初始化从父类继承来的成员。

    java

    复制代码
    public abstract class Animal {
        private String name;
        
        // 抽象类可以有构造方法
        public Animal(String name) {
            this.name = name;
        }
        
        public String getName() {
            return name;
        }
        
        public abstract void eat();
    }
  2. 抽象类中不一定有抽象方法

    • 一个类被 abstract 修饰,它就是抽象类。

    • 但抽象类不一定 包含抽象方法。这种设计通常是为了防止这个类被实例化,而只允许它被继承。

    java

    复制代码
    public abstract class MyBaseClass {
        // 没有抽象方法,但类依然是抽象的
        public void normalMethod() {
            System.out.println("这是一个普通方法");
        }
    }
    // 这个类不能 new MyBaseClass(),只能被继承。
  3. 抽象类中可以包含普通成员

    • 抽象类可以有普通的成员变量普通的成员方法(非抽象方法)

    • 这些普通成员可以直接被子类继承和使用。

五、完整示例

java

复制代码
// 1. 定义抽象类
public abstract class Animal {
    private String name;
    private int age;

    // 抽象类可以有构造方法
    public Animal(String name, int age) {
        this.name = name;
        this.age = age;
    }

    // 抽象方法:定义了一个必须完成的行为规范
    public abstract void eat();

    // 普通方法:子类可以直接继承使用
    public void sleep() {
        System.out.println(name + "正在睡觉");
    }

    // Getter/Setter
    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }
}

// 2. 具体子类:必须重写所有抽象方法
public class Cat extends Animal {
    public Cat(String name, int age) {
        super(name, age); // 调用父类构造方法
    }

    @Override
    public void eat() {
        System.out.println(getName() + "(" + getAge() + "岁)正在吃鱼");
    }
}

// 3. 另一个具体子类
public class Dog extends Animal {
    public Dog(String name, int age) {
        super(name, age);
    }

    @Override
    public void eat() {
        System.out.println(getName() + "(" + getAge() + "岁)正在啃骨头");
    }

    // 子类可以有自己的特有方法
    public void watchHouse() {
        System.out.println(getName() + "在看家");
    }
}

// 4. 测试类
public class Test {
    public static void main(String[] args) {
        // Animal a = new Animal(); // 错误!抽象类不能实例化

        Animal cat = new Cat("小花", 2);
        cat.eat();    // 输出:小花(2岁)正在吃鱼
        cat.sleep();  // 输出:小花正在睡觉

        Dog dog = new Dog("大黄", 3);
        dog.eat();        // 输出:大黄(3岁)正在啃骨头
        dog.watchHouse(); // 输出:大黄在看家
    }
}

// 5. 抽象子类示例(不重写抽象方法)
public abstract class Bird extends Animal {
    // 没有重写 eat() 方法,所以 Bird 也必须是抽象类
    public Bird(String name, int age) {
        super(name, age);
    }

    // 可以定义新的抽象方法
    public abstract void fly();
}

// 6. 最终的具体类,需要实现所有抽象方法(包括Animal的和Bird的)
public class Sparrow extends Bird {
    public Sparrow(String name, int age) {
        super(name, age);
    }

    @Override
    public void eat() { // 实现 Animal 的 eat()
        System.out.println(getName() + "正在吃虫子");
    }

    @Override
    public void fly() { // 实现 Bird 的 fly()
        System.out.println(getName() + "正在飞翔");
    }
}

六、抽象类 vs 普通类 vs 接口

特性 普通类 抽象类 接口
实例化 可以直接实例化 不能直接实例化 不能直接实例化
方法 全是具体方法 可以有具体方法和抽象方法 Java 8前全是抽象方法,之后可以有默认/静态方法
构造方法 没有
成员变量 任意类型 任意类型 只能是 public static final 常量
继承/实现 单继承 单继承 多实现
设计目的 具体实现 模板设计,部分实现,部分规范 纯规范,定义行为契约

七、总结

  1. 抽象类是一个"半成品"类,它定义了部分实现,也声明了部分必须由子类完成的规范(抽象方法)。

  2. 核心作用代码复用 + 强制规范。既提取了共性代码,又强制子类必须实现特定行为。

  3. 使用场景:当多个相关类有共同的属性和行为,但某些行为的具体实现各不相同时。

  4. 设计理念 :"面向抽象编程",依赖于抽象(父类或接口)而非具体实现,提高了代码的灵活性和可扩展性。

java 复制代码
package abstract02;

public class Test {
    public static void main(String[] args) {
        Frog f = new Frog(1, "wawa");
        System.out.println(f.getName()+", "+f.getAge());
        f.drink();
        f.eat();
        f.swim();

        Dog d = new Dog(5, "wangwang");
        System.out.println(d.getName()+", "+d.getAge());
        d.drink();
        d.eat();
        d.swim();

        Sheep s = new Sheep(6, "miemie");
        System.out.println(s.getName()+", "+s.getAge());
        s.drink();
        s.eat();
    }
}


package abstract02;

public abstract class Animal {
    private String name;
    private int age;

    public Animal() {
    }

    public Animal(int age, String name) {
        this.age = age;
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void drink(){
        System.out.println("动物在喝水");
    }

    public abstract void eat();
}


package abstract02;

public class Dog extends Animal implements Swim{

    public Dog() {
    }

    public Dog(int age, String name) {
        super(age, name);
    }

    @Override
    public void eat() {
        System.out.println("狗在吃骨头");
    }

    @Override
    public void swim() {
        System.out.println("狗在游泳");
    }
}


package abstract02;

public  class Frog extends Animal implements Swim{

    public Frog() {
    }

    public Frog(int age, String name) {
        super(age, name);
    }

    @Override
    public void eat() {
        System.out.println("青蛙在吃虫子");
    }

    @Override
    public void swim(){
        System.out.println("青蛙在游泳");

    }
}


package abstract02;

public class Sheep extends Animal{
    public Sheep() {
    }

    public Sheep(int age, String name) {
        super(age, name);
    }

    @Override
    public void eat() {
        System.out.println("🐏在吃草");
    }

}


package abstract02;

public interface Swim {
    public abstract void swim();

}
相关推荐
西岸行者3 天前
学习笔记:SKILLS 能帮助更好的vibe coding
笔记·学习
悠哉悠哉愿意3 天前
【单片机学习笔记】串口、超声波、NE555的同时使用
笔记·单片机·学习
别催小唐敲代码3 天前
嵌入式学习路线
学习
毛小茛3 天前
计算机系统概论——校验码
学习
babe小鑫3 天前
大专经济信息管理专业学习数据分析的必要性
学习·数据挖掘·数据分析
winfreedoms3 天前
ROS2知识大白话
笔记·学习·ros2
在这habit之下3 天前
Linux Virtual Server(LVS)学习总结
linux·学习·lvs
我想我不够好。3 天前
2026.2.25监控学习
学习
im_AMBER3 天前
Leetcode 127 删除有序数组中的重复项 | 删除有序数组中的重复项 II
数据结构·学习·算法·leetcode
CodeJourney_J3 天前
从“Hello World“ 开始 C++
c语言·c++·学习