
本文讲解如何通过构造函数传递对象集合来实现跨类数据共享,避免静态引用或全局变量,确保 pokemon 战斗次数等状态可在 battle 和 catch 类间安全访问。
在 Java 面向对象开发中,直接通过类名访问实例(如 Battle.pikachu)是无效的——因为 Battle 是一个类,不是单例对象,其内部声明的 fire、water 等字段属于实例成员,必须先创建 Battle 对象才能访问。更关键的是,将游戏核心数据(如 Pokemon 实例)硬编码在 GUI 类(Battle extends JFrame)中,会严重破坏职责分离,导致数据无法被 CatchPokemon 等其他业务类复用。
✅ 正确做法是:将 Pokemon 实例的创建与管理权上移至主控制类(如 Main),再通过构造函数注入到需要它的类中。这样既保证了单一数据源,又支持多处共享和状态同步。
以下是一个结构清晰、可扩展的实现方案:
1. 完善 Pokemon 类(支持战斗计数)
public class Pokemon {
private String name;
private String type;
private int defeatCount; // 新增:记录被击败次数
public Pokemon(String name, String type) {
this.name = name;
this.type = type;
this.defeatCount = 0;
}
// 提供安全的访问与修改方法
public void incrementDefeat() {
this.defeatCount++;
}
public int getDefeatCount() {
return defeatCount;
}
public String getName() {
return name;
}
@Override
public String toString() {
return String.format("%s (%s) — Defeated %d time(s)", name, type, defeatCount);
}
}2. 在 Main 类中集中管理 Pokemon 实例
import javax.swing.*;
import java.util.ArrayList;
public class Main {
private ArrayList pokemonList;
public Main() {
initializePokemon();
launchGame();
}
private void initializePokemon() {
pokemonList = new ArrayList<>();
pokemonList.add(new Pokemon("Charmander", "Fire"));
pokemonList.add(new Pokemon("Squirtle", "Water"));
pokemonList.add(new Pokemon("Bulbasaur", "Grass"));
pokemonList.add(new Pokemon("X", "Ground"));
}
private void launchGame() {
// 启动 Battle 界面,并传入共享的 Pokemon 列表
SwingUtilities.invokeLater(() -> {
new Battle(pokemonList).setVisible(true);
});
}
// 提供给 CatchPokemon 等其他模块访问同一份数据
public ArrayList getPokemonList() {
return pokemonList;
}
public static void main(String[] args) {
new Main();
}
} 3. Battle 类接收并操作共享列表
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
public class Battle extends JFrame {
private ArrayList pokemonList;
// 构造函数接收外部传入的 Pokemon 列表
public Battle(ArrayList pokemonList) {
this.pokemonList = pokemonList;
setTitle("Pokemon Battle");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(400, 300);
// 示例:模拟击败 Charmander 一次
for (Pokemon p : pokemonList) {
if ("Charmander".equals(p.getName())) {
p.incrementDefeat(); // 状态变更立即反映到所有持有该引用的地方
System.out.println("✓ " + p); // 输出:Charmander (Fire) — Defeated 1 time(s)
break;
}
}
}
} 4. CatchPokemon 类同样可复用同一列表
public class CatchPokemon {
private ArrayList pokemonList;
public CatchPokemon(ArrayList pokemonList) {
this.pokemonList = pokemonList;
}
public boolean canCatch(String pokemonName, int minDefeats) {
for (Pokemon p : pokemonList) {
if (p.getName().equals(pokemonName) && p.getDefeatCount() >= minDefeats) {
return true;
}
}
return false;
}
} ? 关键注意事项:
立即学习“Java免费学习笔记(深入)”;
- ✅ 所有类共享的是 Pokemon 对象的引用,而非副本,因此 defeatCount 的修改对整个程序可见;
- ❌ 避免使用 static 字段存储 Pokemon 实例(如 public static Pokemon fire = ...),这会阻碍单元测试、多存档支持,并违反面向对象封装原则;
- ⚠️ 若需线程安全(如后台异步战斗逻辑),应对 defeatCount 的读写加锁或使用 AtomicInteger;
- ? 进阶建议:将 pokemonList 封装进 PokemonManager 单例或依赖注入容器,便于统一管理持久化、事件通知等。
通过这种“中心化创建 + 构造注入”的模式,你不仅能解决当前的跨类访问问题,还为后续添加进化系统、图鉴统计、存档功能打下坚实基础。










