14 内部类与匿名类¶
本章目标¶
- 理解内部类的四种形式
- 掌握匿名类(模组事件监听常用)
- 了解静态内部类与局部内部类
- 理解为什么模组代码里到处都是匿名类
14.1 什么是内部类?¶
定义在另一个类里面的类,叫内部类。它可以访问外部类的成员(包括 private)。
public class Player {
private int level = 1;
// 内部类
public class Inventory {
public void show() {
System.out.println("玩家等级: " + level); // 可以访问外部类私有成员
}
}
}
// 使用(非静态内部类需要外部类实例)
Player p = new Player();
Player.Inventory inv = p.new Inventory();
inv.show();
14.2 静态内部类(static nested class)¶
加 static,不持有外部类引用,最常用、最推荐:
public class GameData {
private static int version = 3;
public static class PlayerData { // 静态内部类
private String name;
private int level;
public PlayerData(String name, int level) {
this.name = name;
this.level = level;
}
public String describe() {
// 只能访问外部类的静态成员
return name + " Lv." + level + " (数据版本 " + GameData.version + ")";
}
}
}
// 使用
GameData.PlayerData data = new GameData.PlayerData("小明", 30);
为什么常用
静态内部类不依赖外部类实例,逻辑独立又和外部类相关,是组织代码的好方式。模组里"主类 + 数据类"经常这么搭配。
14.3 局部内部类与匿名类¶
局部内部类:定义在方法里¶
public void run() {
class Helper { // 只在这个方法里用
void help() { System.out.println("帮助中…"); }
}
new Helper().help();
}
匿名类:没有名字,直接 new 接口/抽象类¶
// 普通做法:定义实现类
class Dog implements Soundable {
public void makeSound() { System.out.println("汪汪"); }
}
// 匿名类做法:用一次不命名
Soundable dog = new Soundable() {
@Override
public void makeSound() {
System.out.println("汪汪");
}
};
dog.makeSound();
匿名类适合"只使用一次"的实现,不用单独建类文件。
14.4 模组里最常见的匿名类场景¶
监听事件(Java 8 之前的写法,现在多数用 Lambda,第 16 章):
// 匿名类:实现接口
button.setOnClickListener(new OnClickListener() {
@Override
public void onClick() {
System.out.println("按钮被点击了");
}
});
// Lambda 等价写法(第 16 章)
button.setOnClickListener(() -> System.out.println("按钮被点击了"));
Forge 事件监听也常见:
// Forge 事件总线注册(匿名类风格)
MinecraftForge.EVENT_BUS.register(new Object() {
@SubscribeEvent
public void onPlayerJoin(PlayerEvent.PlayerLoggedInEvent event) {
System.out.println(event.getEntity().getName().getString() + " 加入了游戏");
}
});
14.5 内部类访问外部变量:必须 final/有效 final¶
方法里的局部变量被内部类/匿名类使用时,必须是有效 final(初始化后不再修改):
public void test() {
String msg = "你好"; // 有效 final(后面没改)
Runnable r = new Runnable() {
@Override
public void run() {
System.out.println(msg); // ✅
}
};
int count = 0;
Runnable r2 = new Runnable() {
@Override
public void run() {
// count++; // ❌ 编译错误:count 不是有效 final
}
};
}
14.6 实战:模组场景¶
// 给物品注册右键使用逻辑(匿名类风格示意)
public class MyItems {
public static final Item MAGIC_WAND = new Item(new Item.Properties()) {
@Override
public ActionResult<ItemStack> use(Level level, Player player, InteractionHand hand) {
player.sendSystemMessage(Component.literal("✨ 魔法杖释放了法术!"));
return ActionResult.success(player.getItemInHand(hand));
}
};
}
14.7 小练习¶
- 写一个外部类
School,内部静态类Student(姓名/分数),main 里创建几个学生 - 用匿名类实现一个接口
Greeter { String greet(String name); } - 验证"方法局部变量被匿名类使用必须有效 final"
本章小结¶
- 内部类可以访问外部类成员
- 静态内部类最常用(不依赖外部实例)
- 匿名类适合一次性实现,模组事件监听常见
- 被内部类使用的局部变量必须有效 final
下一章:15 枚举与注解