温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

如何测试java不可变性

发布时间:2026-10-22 09:32:37 来源:亿速云 阅读:87 作者:小樊 栏目:编程语言

在 Java 中,“不可变性(Immutability)”通常指对象创建后其状态不能被修改。测试不可变性,就是验证:无论怎么“操作”,原对象都不会发生变化。

下面从思路 → 常见测试方法 → 示例 → 工具系统说明。


一、不可变性的核心判断标准

一个类是不可变的,通常满足:

  1. 类用 final 修饰(防止继承破坏)
  2. 所有字段是 private final
  3. 不提供 setter
  4. 对可变对象(如 List、Date):
    • 不暴露引用
    • 构造时防御性拷贝
    • 返回时防御性拷贝

二、测试不可变性的基本思路

核心原则:

修改“看起来能改的东西”,然后检查原对象是否变化


三、常见测试方法(重点)

1️⃣ 测试没有 setter / 可变方法

@Test
public void shouldNotHaveSetter() throws Exception {
    Method[] methods = User.class.getDeclaredMethods();
    for (Method m : methods) {
        assertFalse(m.getName().startsWith("set"));
    }
}

2️⃣ 测试字段不能被修改(反射尝试)

@Test
public void fieldShouldNotBeModified() throws Exception {
    User user = new User("Tom");
    Field field = User.class.getDeclaredField("name");
    field.setAccessible(true);
    field.set(user, "Jerry");

    assertEquals("Tom", user.getName());
}

✅ 若抛异常或值不变 → 不可变


3️⃣ 测试返回的可变对象不影响原对象(防御性拷贝)

@Test
public void listShouldBeDefensiveCopy() {
    List<String> tags = new ArrayList<>();
    tags.add("a");

    Config config = new Config(tags);
    config.getTags().add("b");

    assertEquals(1, config.getTags().size());
}

4️⃣ 测试构造参数修改不影响对象

@Test
public void constructorDefensiveCopy() {
    List<String> list = new ArrayList<>();
    list.add("x");

    Container c = new Container(list);
    list.add("y");

    assertEquals(1, c.getList().size());
}

5️⃣ 测试“修改方法”返回新对象

@Test
public void withMethodReturnsNewInstance() {
    Point p1 = new Point(1, 2);
    Point p2 = p1.withX(10);

    assertNotSame(p1, p2);
    assertEquals(1, p1.getX());
}

四、使用第三方工具测试不可变性

✅ 1. Mutability Detector(推荐)

<dependency>
  <groupId>org.mutabilitydetector</groupId>
  <artifactId>MutabilityDetector</artifactId>
  <version>0.10.1</version>
</dependency>
@Test
public void shouldBeImmutable() {
    assertImmutable(User.class);
}

✅ 2. ArchUnit(架构级约束)

classes().that().resideInAPackage("..domain..")
         .should().beImmutable()

✅ 3. Record(Java 14+ 天然不可变)

record User(String name) {}

✅ 编译器保证不可变


五、容易被忽略的“假不可变”

❌ 以下不是真正不可变:

public final class Bad {
    private final List<String> list;
    public List<String> getList() {
        return list; // 暴露可变引用
    }
}

六、总结

测试不可变性 = 尝试破坏 + 验证不变

测试方向 是否必要
无 setter ✅
反射改字段 ✅
可变对象拷贝 ✅
返回新对象 ✅
工具检测 ✅✅

如果你有具体类代码,我可以直接帮你写不可变性测试用例。

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI
助
手