CodeGym /课程 /JAVA 25 SELF /创建类层次结构,贴近生活的示例

创建类层次结构,贴近生活的示例

JAVA 25 SELF
第 17 级, 课程 3
可用

1. 什么是类的层次结构?

在编程中(以及其他领域),层次结构——是一种树形结构:树的顶部是“通用”的实体(基类),下面——是更具体的实体(子类)。在 Java 中,类的层次结构通过继承来构建:每个子类本身也可以作为其他子类的父类,依次类推。

类比:

  • 动物(Animal)是通用的类。
  • 哺乳动物(Mammal)是动物的特例。
  • 狗(Dog)是哺乳动物的特例。
  • 而具体的“沙里克”——就是 Dog 类的一个对象。

在代码中看起来如下:

class Animal { }
class Mammal extends Animal { }
class Dog extends Mammal { }

类的层次结构允许在“上层”描述通用属性和行为,而在“下层”描述细节。这使代码更有逻辑,也能避免重复。

层次结构示意图

Animal
├── Mammal
│   ├── Dog
│   └── Cat
└── Bird
    └── Sparrow

2. 如何构建层次结构:思路与实践

辨别共性与特性

核心规则:基类应包含对其所有后代都适用的内容;而所有独有的内容——放到子类中。

示例:

  • 所有动物都会呼吸和进食——因此,方法 breathe() 和 eat() 应该在 Animal 类中。
  • 只有鸟会飞——因此,方法 fly() 应在 Bird 类中,而不是在 Animal 中。
  • 只有狗会叫——方法 bark() 应在 Dog 类中。

示例:动物

// 基类
class Animal {
    String name;

    Animal(String name) {
        this.name = name;
    }

    void eat() {
        System.out.println(name + " 在吃。");
    }

    void makeSound() {
        System.out.println(name + " 发出声音。");
    }
}

// 子类:哺乳动物
class Mammal extends Animal {
    Mammal(String name) {
        super(name);
    }

    void feedMilk() {
        System.out.println(name + " 用奶喂幼崽。");
    }
}

// 子类:狗
class Dog extends Mammal {
    Dog(String name) {
        super(name);
    }

    @Override
    void makeSound() {
        System.out.println(name + " 在汪汪叫:汪汪!");
    }

    void wagTail() {
        System.out.println(name + " 摇尾巴。");
    }
}

// 子类:猫
class Cat extends Mammal {
    Cat(String name) {
        super(name);
    }

    @Override
    void makeSound() {
        System.out.println(name + " 在喵喵叫:喵!");
    }

    void purr() {
        System.out.println(name + " 打呼噜。");
    }
}

// 子类:鸟
class Bird extends Animal {
    Bird(String name) {
        super(name);
    }

    void fly() {
        System.out.println(name + " 在飞。");
    }

    @Override
    void makeSound() {
        System.out.println(name + " 在叽喳叫:叽喳叽喳!");
    }
}

在 main 中的调用:

public class ZooDemo {
    public static void main(String[] args) {
        Dog buddy = new Dog("沙里克");
        Cat kitty = new Cat("穆尔卡");
        Bird sparrow = new Bird("麻雀");

        buddy.eat();        // 沙里克 在吃。
        buddy.makeSound();  // 沙里克 在汪汪叫:汪汪!
        buddy.feedMilk();   // 沙里克 用奶喂幼崽。
        buddy.wagTail();    // 沙里克 摇尾巴。

        kitty.eat();         // 穆尔卡 在吃。
        kitty.makeSound();   // 穆尔卡 在喵喵叫:喵!
        kitty.feedMilk();    // 穆尔卡 用奶喂幼崽。
        kitty.purr();        // 穆尔卡 打呼噜。

        sparrow.eat();       // 麻雀 在吃。
        sparrow.makeSound(); // 麻雀 在叽喳叫:叽喳叽喳!
        sparrow.fly();       // 麻雀 在飞。
    }
}

可视化:类树

类 父类 特性
Animal
Object
name, eat(), makeSound()
Mammal
Animal
feedMilk()
Dog
Mammal
makeSound(), wagTail()
Cat
Mammal
makeSound(), purr()
Bird
Animal
fly(), makeSound()

3. 更多生活化示例

几何图形

类的层次结构非常适合建模几何图形。

// 基类
class Shape {
    void draw() {
        System.out.println("绘制图形。");
    }
}

// 圆
class Circle extends Shape {
    double radius;

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

    @Override
    void draw() {
        System.out.println("绘制半径为 " + radius + " 的圆");
    }
}

// 矩形
class Rectangle extends Shape {
    double width, height;

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

    @Override
    void draw() {
        System.out.println("绘制矩形 " + width + "x" + height);
    }
}

用法:

public class ShapeDemo {
    public static void main(String[] args) {
        Shape s1 = new Circle(5);
        Shape s2 = new Rectangle(3, 4);

        s1.draw(); // 绘制半径为 5.0 的圆
        s2.draw(); // 绘制矩形 3.0x4.0
    }
}

交通工具

class Vehicle {
    void move() {
        System.out.println("交通工具在移动。");
    }
}

class Car extends Vehicle {
    @Override
    void move() {
        System.out.println("汽车在路上行驶。");
    }
}

class Bicycle extends Vehicle {
    @Override
    void move() {
        System.out.println("骑行者在蹬踏板。");
    }
}

main:

Vehicle v1 = new Car();
Vehicle v2 = new Bicycle();

v1.move(); // 汽车在路上行驶。
v2.move(); // 骑行者在蹬踏板。

用户

class User {
    String username;
    User(String username) { this.username = username; }
    void login() { System.out.println(username + " 登录系统。"); }
}

class Admin extends User {
    Admin(String username) { super(username); }
    void deleteUser(String user) {
        System.out.println(username + " 删除了用户 " + user);
    }
}

class Customer extends User {
    Customer(String username) { super(username); }
    void buy() { System.out.println(username + " 完成了一次购买。"); }
}

4. 有用的细节

不要滥用继承。 继承是用于“is-a”关系的工具。如果你要表达“猫是动物”,使用继承。若是“猫包含尾巴”,应使用组合(has-a)。

不好:

class Engine { /* ... */ }
class Car extends Engine { /* 汽车就是发动机吗?不,这是组合! */ }

好:

class Car {
    Engine engine; // 汽车包含发动机
}

不要把层次搞得过深。 层次越多——就越难维护和理解代码。通常 2–3 层已经足以覆盖大多数任务。

也不要过于“扁平”。 如果你有 20 个类都直接继承自一个基类,可能需要重新审视架构。

为“图省事”而继承。 有时会想“不管逻辑,先把方法或字段拿来再说”。这是走向混乱的开始!如果 class A 和 class B 在逻辑上并无关系,不要仅仅为了几个方法就让 extends 发生在 B 和 A 之间。

违反里氏替换原则。 如果子类无法在不带来意外的前提下替代父类使用——说明你的层次结构设计有问题。

代码重复。 如果你发现“哎,这个方法在好几个类里都复制了一份”,那也许就该把它上移到基类中了。

5. 构建类层次结构时的常见错误

错误 No.1:没有“is-a”语义的继承。
如果你使用继承只是为了获得方法或字段的访问权,而不是因为子类确实“是”父类的一种,那么你的代码很快就会变成一锅粥。比如,“汽车继承发动机”——这不是 is-a,而是 has-a。

错误 No.2:忽略子类的独特特性。
如果所有子类看起来都一样,且没有增加任何新内容,那么可能根本不需要层次结构——使用一个类即可。

错误 No.3:在子类中重复代码。
如果你把同样的实现复制到多个子类中,应该考虑把它上移到父类。

错误 №4:层次过于复杂或过深。
多层级的层次结构难以维护和测试。越简单——越好!

错误 №5:重写方法却不使用 @Override 注解。
没有注解就很容易在方法签名上出错,这样方法并不会被正确重写,而是会被当成新方法。请始终使用 @Override!

1
任务
JAVA 25 SELF, 第 17 级, 课程 3
已锁定
虚拟宠物:Bobik 在吃 🐕
虚拟宠物:Bobik 在吃 🐕
1
任务
JAVA 25 SELF, 第 17 级, 课程 3
已锁定
驾校:移动与信号 🚦
驾校:移动与信号 🚦
1
任务
JAVA 25 SELF, 第 17 级, 课程 3
已锁定
学校层级:我是谁? 🎓
学校层级:我是谁? 🎓
1
任务
JAVA 25 SELF, 第 17 级, 课程 3
已锁定
动物百科:猫的特征 🐈
动物百科:猫的特征 🐈
评论 (2)
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION
悠 级别 1,-,Hong Kong
2 九月 2026
越过無人区,终于看到评论了
ncksllpo 级别 45,Cherkasy,Ukraine
2 二月 2026
🤑