跳转至

08 继承与多态

本章目标

  • 理解继承:子类复用父类代码
  • 掌握 super、方法重写
  • 掌握抽象类与 final
  • 理解多态:父类引用指向子类对象

8.1 什么是继承?

继承:子类(subclass)继承父类(superclass)的属性和方法,还能添加自己的、重写父类的。

父类:Animal(动物)
  ├── name、eat()、sleep()
  │
  ├── 子类:Dog(狗)
  │     └── 新增 bark()
  │
  └── 子类:Cat(猫)
        └── 新增 meow()
// 父类
public class Animal {
    protected String name;     // protected:子类可以访问

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

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

// 子类:extends 继承
public class Dog extends Animal {
    public Dog(String name) {
        super(name);           // 调用父类构造器(必须放在第一行)
    }

    public void bark() {
        System.out.println(name + " 汪汪叫");
    }
}

使用:

Dog dog = new Dog("旺财");
dog.eat();      // 继承来的方法
dog.bark();     // 自己的方法

8.2 super 关键字

  • super(...):调用父类构造器(子类构造器第一行)
  • super.方法():调用父类被重写的方法
public class Dog extends Animal {
    public Dog(String name) {
        super(name);
    }

    @Override
    public void eat() {
        System.out.println("先闻一闻…");
        super.eat();     // 再调用父类的 eat
    }
}

8.3 方法重写(Override)

子类重新实现父类的方法,叫重写。加上 @Override 注解让编译器帮忙检查:

public class Cat extends Animal {
    public Cat(String name) {
        super(name);
    }

    @Override
    public void eat() {
        System.out.println(name + " 在优雅地吃鱼");
    }
}

重写 vs 重载

重写 Override 重载 Overload
位置 子类重写父类方法 同类多个同名方法
方法签名 完全一样 参数不同
关键词 @Override 无

8.4 多态

多态:父类类型的引用,可以指向子类对象。调用方法时,实际执行子类的实现:

Animal a1 = new Dog("旺财");   // 父类引用指向子类对象
Animal a2 = new Cat("咪咪");

a1.eat();    // 调用的是 Dog 的 eat(如果有重写)
a2.eat();    // 调用的是 Cat 的 eat

a1.bark();   // ❌ 编译错误!Animal 类型没有 bark 方法

好处:写代码时面向父类(通用),运行时自动分派到具体子类。

// 一个方法处理所有动物
static void feed(Animal animal) {
    animal.eat();    // 传入 Dog 就执行 Dog 的 eat
}

feed(new Dog("旺财"));
feed(new Cat("咪咪"));

instanceof 判断实际类型

Animal a = new Dog("旺财");
if (a instanceof Dog) {
    Dog dog = (Dog) a;     // 向下转型
    dog.bark();
}

// Java 16+ 更简洁的写法
if (a instanceof Dog dog) {
    dog.bark();
}

8.5 抽象类(abstract)

抽象类不能 new,用来规定"子类必须实现什么"。抽象方法没有方法体,子类必须重写:

public abstract class Weapon {
    protected String name;
    protected int damage;

    public Weapon(String name, int damage) {
        this.name = name;
        this.damage = damage;
    }

    public abstract void use();    // 抽象方法:没有方法体

    public String getName() {      // 普通方法:子类可以直接用
        return name;
    }
}

public class Sword extends Weapon {
    public Sword(String name, int damage) {
        super(name, damage);
    }

    @Override
    public void use() {            // 必须实现
        System.out.println("挥动 " + name + ",造成 " + damage + " 点伤害");
    }
}

模组里的抽象类

Forge 里 Item、Block 是普通类,但很多扩展点设计成抽象类/接口(如 IItemExtension)。你写模组类时经常要 extends 某个类并 @Override 方法。

8.6 final 在继承中的三种用法

位置 含义
final 变量 值不可改(常量)
final 方法 子类不能重写
final 类 不能被继承
final class MathHelper { ... }        // 不能被继承(如工具类)
public final void onUse() { ... }     // 子类不能重写

8.7 Object 类

所有类都直接或间接继承 Object。常用方法:

  • toString():返回字符串描述(默认是 类名@地址,一般重写)
  • equals(Object):比较内容(String 就重写了它)
  • hashCode():哈希值(配合集合用)
@Override
public String toString() {
    return "Player{name='" + name + "', level=" + level + "}";
}

IDEA 里 Generate → toString() 一键生成。

8.8 实战:模组场景

// 简化版:自定义方块类(真实模组继承 Block)
public abstract class CustomBlock {
    protected final String id;
    protected boolean transparent;

    public CustomBlock(String id) {
        this.id = id;
    }

    public abstract boolean canStandOn();

    public String getDisplayName() {
        return "方块[" + id + "]";
    }
}

public class SteelBlock extends CustomBlock {
    public SteelBlock() {
        super("ffs_steel_block");
        this.transparent = false;
    }

    @Override
    public boolean canStandOn() {
        return true;
    }
}

8.9 小练习

  1. 设计父类 Shape(抽象方法 area()),子类 Circle(半径)和 Rect(长宽),分别实现面积
  2. 写一个 main:用 Shape 引用数组装多个子类对象,循环调用 area(),观察多态
  3. 给 Animal 加一个 toString() 重写,输出名字

本章小结

  • extends 继承,super 调父类
  • @Override 重写方法实现多态
  • 抽象类不能 new,抽象方法子类必须实现
  • final 阻止继承/重写/修改
  • 一切类继承自 Object

下一章:09 接口

🏠 返回总站