二维数组作为对象成员必须封装,禁止直接暴露引用;应设为private,提供深拷贝只读访问、带校验的单元素修改及批量初始化接口,并可按业务抽象为带语义的嵌套结构。

二维数组作为对象成员时,不能简单当作普通字段暴露给外部,必须结合封装原则控制其访问方式和修改逻辑。核心在于:数组本身是引用类型,直接提供 public 字段或 getter 返回原始数组引用,会导致外部绕过校验随意修改内容,破坏对象状态一致性。
避免直接暴露数组引用
错误做法是把二维数组声明为 public,或通过 getter 直接返回数组本身:
❌ 不安全示例:public int[][] scores = {{85, 92}, {78, 88}};
public int[][] getScores() { return scores; } // 外部可直接 scores[0][1] = 100;
这会让调用方跳过所有业务规则(如分数范围校验、行/列维度约束),造成数据污染。
提供受控的读写接口
应将二维数组设为 private,并按需提供以下三类方法:
-
只读访问:用深拷贝或不可变包装返回副本,例如:
public int[][] getScoresCopy() {<br> int[][] copy = new int[scores.length][];<br> for (int i = 0; i copy[i] = scores[i].clone(); // 每行浅拷贝即可<br> }<br> return copy;<br> } -
单点赋值:带边界与业务校验,例如设置某学生某科成绩:
public void setScore(int studentIndex, int subjectIndex, int score) {<br> if (studentIndex = scores.length) throw new IndexOutOfBoundsException();<br> if (subjectIndex = scores[studentIndex].length) throw new IndexOutOfBoundsException();<br> if (score 100) throw new IllegalArgumentException("分数必须在0-100之间");<br> scores[studentIndex][subjectIndex] = score;<br> } -
批量初始化:用静态工厂方法或构造器完成整体构建,避免中途不一致状态:
public ScoreSystem(int[][] initialScores) {<br> if (initialScores == null) throw new IllegalArgumentException();<br> this.scores = deepCopy(initialScores); // 自定义深拷贝逻辑<br> }
结合业务场景做维度抽象
硬编码 int[][] 容易丢失语义。更优策略是将二维结构映射为有含义的嵌套对象,例如:
- 用
List<student></student>替代外层数组,每个Student内含List<subjectscore></subjectscore>; - 或定义
class ScoreMatrix { private final int[][] data; private final String[] students; private final String[] subjects; },把行列标签也纳入封装; - 这样既保留二维索引能力,又支持按姓名查成绩、按科目统计平均分等自然操作。
内存与性能的务实权衡
频繁 clone 二维数组有开销,但安全优先。若性能敏感且确认外部可信,可用“防御性返回”替代全量拷贝:
- 对外只返回每行的
int[]::clone(一维拷贝),不复制整个二维结构; - 或提供只读视图方法,如
int getScore(int i, int j),不暴露底层数组; - 避免在 getter 中新建数组,除非明确需要副本。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











