Lombok 值注释对于不可变 java 类无法正常工作

Gep*_*Gep 1 java immutability lombok

我想看看是否可以使用 Lombok 创建一个不可变的 Java 类。我在 Lombok 网站上找到了这个页面“不可变类变得非常容易”,但我不相信它: https: //projectlombok.org/features/Value

我已经使用他们在该页面中使用的示例类对其进行了测试,即

@Value
public class ValueExample {
  String name;
  @With(AccessLevel.PACKAGE) @NonFinal int age;
  double score;
  protected String[] tags;
  
  @ToString(includeFieldNames=true)
  @Value(staticConstructor="of")
  public static class Exercise<T> {
    String name;
    T value;
  }
}
Run Code Online (Sandbox Code Playgroud)

并写了一个小测试:

public static void main(String... args) {

    String tags[] = {"a", "b", "c"};

    ValueExample t = new ValueExample("name", 1, 2.3, tags);

    System.out.println("BEFORE:" + Arrays.toString(t.getTags()));

    String[] tagsToModify = t.getTags();

    for (int i = 0; i < tags.length; i++) {
        tagsToModify[i] = "?";
    }

    System.out.println("AFTER: " + Arrays.toString(t.getTags()));
}
Run Code Online (Sandbox Code Playgroud)

测试的输出是:

BEFORE:[a, b, c]
AFTER: [?, ?, ?]
Run Code Online (Sandbox Code Playgroud)

对我来说这意味着类不是一成不变的。我错过了一些明显的东西吗?

use*_*612 6

问题是tags是一个Array,因此是一个引用类型,并且数组是可变的。虽然您确实无法更改其值tags(例如,您无法重新分配它以引用不同的数组),但它引用的数组可以由持有对它的引用的任何人(包括类ValueExample本身,或main您创建的用于测试此行为的方法)。

\n

暂时将反射放在一边(因为它提供了一个破坏不变性的“后门”),对于真正不可变的类,所有引用的属性也应该是不可变的 \xe2\x80\x93 并且 Array 不是 \xe2\x80 \x93 或者你可能不得不求助于防御性复制等技术。

\n

作为补充说明,您还需要在 getter 中返回不可变对象。tags想象一下,您在构造函数中创建了数组的防御性副本。如果您在 中返回副本getTags(),则任何可以调用该 getter 的人也都能够改变该数组(同样,因为数组是可变的)。因此,理想情况下,您需要在构造函数和 getter 中创建一个新副本。如果数组很大,这很容易变得相当昂贵......最重要的是,数组中的每个项目也应该是不可变的,否则任何有权访问数组的人也可以改变这些对象。

\n