识别“误解值传递”Bug的关键是检查基本类型赋值、对象引用传递和数组/集合浅拷贝行为是否被混淆,重点审查数组直接赋值修改、自定义对象传参后字段修改、返回集合或数组未做防御性拷贝三类高危场景。

在Java代码审查中识别“误解值传递”引发的Bug,关键不是看语法是否合法,而是看开发者是否混淆了基本类型赋值、对象引用传递和数组/集合的浅拷贝行为。这类Bug不会报编译错误,运行时也常能“凑合跑通”,但一旦涉及数据修改、多线程或跨方法共享,就会暴露副作用——比如改了新对象,原对象也变了;或者以为传的是副本,实则共用同一份内存。
重点盯住这三类高危场景
以下情况出现频率高、后果隐蔽,应作为审查时的必查项:
-
数组直接赋值后做修改:如
int[] copy = original;后对copy[0] = 99,原数组同步被改。这不是拷贝,是别名。应检查是否误用此写法替代Arrays.copyOf或System.arraycopy。 -
自定义对象传参后修改字段:方法签名形如
void process(User user),内部执行user.setName("xxx")。若调用方后续还依赖该对象原始状态,就埋下隐患。需确认该修改是否属于预期副作用,否则应明确注释或改用不可变对象/深拷贝。 -
返回集合或数组却不做防御性拷贝:例如方法返回
private List<string> tags = new ArrayList<>();</string>的直引,外部拿到后tags.add(...)会污染内部状态。审查时要查 getter 是否用了Collections.unmodifiableList或返回新副本。
看方法边界是否做了“隔离”
值传递的理解偏差,往往在方法输入/输出边界暴露最明显。审查时可问三个问题:
- 这个参数进来后,方法会不会改变它的内容(而非仅读取)?如果会,是否与调用方契约一致?
- 这个方法返回的对象,是新建的、只读的,还是内部持有的可变引用?
- 如果同一对象被多个线程访问,当前操作是否线程安全?比如用
ArrayList而未加锁或替换为CopyOnWriteArrayList。
借助工具辅助发现典型模式
人工审查易漏,可结合静态分析工具快速定位风险点:
立即学习“Java免费学习笔记(深入)”;
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
-
FindBugs / SpotBugs:检测
DC: Doubled checked locking、MS: Mutable static field、EI: May expose internal representation等规则,直接标出“可能暴露内部可变状态”的代码行。 - IDEA 内置检查:启用 “Mutable collection passed as argument”、“Collection is accessed after being returned from method” 等提示,会在代码编辑时高亮可疑调用。
- 阿里代码审计插件:对违反《阿里巴巴Java开发手册》中“禁止返回数组或集合的原始引用”等条款的代码实时告警。
用最小测试反推行为是否符合直觉
遇到疑似误解值传递的逻辑,不靠猜,写一段两行测试即可验证:
示例:审查到如下方法public List<String> getNames() { return this.names; }
List<String> list = obj.getNames();<br>list.add("new");<br>assertThat(obj.getNames()).doesNotContain("new"); // 应该通过,但实际失败 → 暴露问题
这种“反常识断言”能快速揪出隐性共享,比读十遍代码更可靠。

















