Java是值传递,即传递引用的副本:基本类型参数修改不影响实参,对象参数可修改其状态但无法改变引用指向。

Java 中的“值传递”本质是传递引用的副本,不是对象本身,也不是传统意义上的纯值(如 int 的拷贝)。要验证这一行为,单元测试的关键不在于“证明 Java 是值传递”,而在于通过可观察的副作用差异,清晰区分‘修改引用’和‘修改对象状态’两种操作的效果。
验证基本类型参数不可被方法内修改影响
这是最直观的验证点:方法内对形参重新赋值,不会影响实参。
@Test
void givenPrimitive_whenModifiedInMethod_thenOriginalUnchanged() {
int original = 42;
modifyPrimitive(original);
assertEquals(42, original); // ✅ 通过
}
void modifyPrimitive(int x) {
x = 99; // 修改的是 x 的副本,不影响 original
}
验证对象引用参数可被用于修改对象状态(但不能改变引用指向)
重点设计两个对比场景:一个是调用对象方法改变其内部字段(可见),另一个是让形参指向新对象(不可见)。
@Test
void givenObjectReference_whenStateModified_thenChangesVisible() {
StringBuilder sb = new StringBuilder("hello");
appendWorld(sb);
assertEquals("helloworld", sb.toString()); // ✅ 通过:对象状态被修改
}
void appendWorld(StringBuilder b) {
b.append("world"); // 操作的是 b 所指向的对象,与 sb 共享同一实例
}
@Test
void givenObjectReference_whenReassigned_thenOriginalReferenceUnchanged() {
StringBuilder sb = new StringBuilder("hello");
reassignReference(sb);
assertEquals("hello", sb.toString()); // ✅ 通过:sb 仍指向原对象
}
void reassignReference(StringBuilder b) {
b = new StringBuilder("new"); // b 现在指向新对象,但 sb 不受影响
}
验证自定义类中体现相同逻辑(增强说服力)
避免依赖 String、StringBuilder 等有特殊语义的类。用简单 POJO 更能聚焦机制本身。
立即学习“Java免费学习笔记(深入)”;
static class Person {
String name;
int age;
Person(String name, int age) { this.name = name; this.age = age; }
}
@Test
void givenCustomObject_whenFieldModified_thenVisible() {
Person p = new Person("Alice", 30);
changeName(p);
assertEquals("Bob", p.name); // ✅
}
void changeName(Person person) {
person.name = "Bob"; // 修改对象字段 → 外部可见
}
@Test
void givenCustomObject_whenReassigned_thenOriginalUnchanged() {
Person p = new Person("Alice", 30);
replacePerson(p);
assertEquals("Alice", p.name); // ✅
assertEquals(30, p.age);
}
void replacePerson(Person person) {
person = new Person("Charlie", 40); // person 指向新对象,p 不变
}
避免常见误解的测试写法
以下测试看似合理,实则混淆概念,不应作为“验证值传递”的证据:
- 用
String做实验并断言内容不变 —— 因为String不可变,不是因为传递机制;换StringBuilder就变了 - 测试
==比较引用是否相等 —— 这验证的是引用一致性,不是传递方式 - 试图用反射或 Unsafe 检查内存地址 —— 超出单元测试范畴,且无必要


















