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 小练习¶
- 设计父类
Shape(抽象方法 area()),子类Circle(半径)和Rect(长宽),分别实现面积 - 写一个
main:用Shape引用数组装多个子类对象,循环调用 area(),观察多态 - 给 Animal 加一个
toString()重写,输出名字
本章小结¶
- extends 继承,super 调父类
- @Override 重写方法实现多态
- 抽象类不能 new,抽象方法子类必须实现
- final 阻止继承/重写/修改
- 一切类继承自 Object
下一章:09 接口