本文介绍如何避免硬编码二维数组索引,通过封装图像信息为独立类并结合集合迭代,实现更安全、可维护的java图像批量绘制逻辑。
本文介绍如何避免硬编码二维数组索引,通过封装图像信息为独立类并结合集合迭代,实现更安全、可维护的java图像批量绘制逻辑。
在原始代码中,使用 String[][] ships 存储图像文件名、宽度和高度(如 {"Bismarck.png","Rodney.png"}, {"170","50"}, {"20","220"}),看似简洁,实则隐含严重设计缺陷:
- 索引耦合性强:依赖行与列的严格对应关系(第0行是文件名、第1行是宽度、第2行是高度),极易因顺序错乱或新增字段导致 ArrayIndexOutOfBoundsException;
- 语义不清晰:ships[i][0]、ships[i][1] 等无法表达业务含义,可读性差,维护成本高;
- 循环逻辑错误:原 createScene() 中嵌套循环方向颠倒(外层遍历 ships[0].length,内层遍历 ships.length),实际会越界访问且重复调用 drawImage 多达 3×2=6 次,而非预期的 2 次(每艘船一次)。
✅ 正确解法是面向对象重构:将每艘船的图像信息封装为独立实体类,再交由集合统一管理。
1. 定义 ShipImage 实体类
public class ShipImage {
private final String fileName;
private final int width; // 推荐使用 int 而非 String,便于后续计算
private final int height;
public ShipImage(String fileName, int width, int height) {
this.fileName = fileName;
this.width = width;
this.height = height;
}
// Getter 方法(必要时可添加)
public String getFileName() { return fileName; }
public int getWidth() { return width; }
public int getHeight() { return height; }
}
? 注意:将 width/height 声明为 int 类型,既避免字符串解析开销,又增强类型安全性;final 保证不可变性,符合领域模型最佳实践。
2. 使用 List 替代二维数组(推荐有序场景)
// 在 main 方法中
List<shipimage> shipImages = Arrays.asList(
new ShipImage("Bismarck.png", 170, 20),
new ShipImage("Rodney.png", 50, 220)
);
BattleScene scene = new BattleScene(shipImages);</shipimage>
3. 更新 BattleScene 类以支持集合迭代
public class BattleScene {
private final List<shipimage> shipImages;
public BattleScene(List<shipimage> shipImages) {
this.shipImages = Objects.requireNonNull(shipImages, "shipImages cannot be null");
}
public void createScene() {
for (ShipImage ship : shipImages) {
drawImage(ship.getFileName(), ship.getWidth(), ship.getHeight(), 250, 7);
}
}
// 假设 drawImage 是已存在的绘图方法
private void drawImage(String fileName, int width, int height, int x, int y) {
// 实际绘制逻辑(如 Swing/AWT 或 JavaFX 调用)
System.out.printf("Drawing %s at (%d,%d) with size %dx%d%n",
fileName, x, y, width, height);
}
}</shipimage></shipimage>
✅ 关键优势总结
- 零索引风险:无需手动计算 ships[i][j],编译器保障字段访问安全;
- 扩展友好:新增属性(如 rotationAngle、opacity)只需修改 ShipImage 类,不影响 BattleScene 循环逻辑;
- 测试友好:可单独对 ShipImage 单元测试,BattleScene.createScene() 逻辑极简,专注流程控制;
- 符合单一职责原则:BattleScene 只负责场景调度,图像数据结构由 ShipImage 承担。
⚠️ 若坚持使用二维数组(不推荐),至少应校验数组维度:
if (ships.length <p>但此方案仍无法规避运行时类型转换异常与语义模糊问题——<strong>面向对象才是根本解法</strong>。</p>











