我有一个名为 Employees
的不可变类,如下所示:
public final class Employees {
private final List<Person> persons;
public Employees() {
persons = new LinkedList<Person>();
}
public List<Person> getPersons() {
return persons;
}
}
如何保持这个类不可变?
我将字段 private
和 final
设为了,我没有提供 setter 方法。这足以实现不变性吗?
最佳答案
答案已编辑,不仅解释了可变版本 Person
的情况,还解释了不可变版本 Person
的情况。
你的类是可变的,因为你可以这样做:
Employees employees = new Employees();
employees.getPersons().add(new Person());
请注意,如果您更改代码以创建不可变类,则不将人员列表传递给构造函数,您将拥有一个无用的类,其中包含一个空的人员列表,因此我认为有必要将 List<Person>
传递给构造函数。
现在有两种场景,不同的实现方式:
-
Person
是不可变的 -
Person
是可变的
场景 1 - Person
是不可变的
您只需要在构造函数中创建persons参数的不可变副本。
您还需要将 final
设为类或至少将方法设为 getPersons
,以确保没有人提供 getPersons
方法的可变覆盖版本。
public final class Employees {
private final List<Person> persons;
public Employees(List<Person> persons) {
persons = Collections.unmodifiableList(new ArrayList<>(persons));
}
public List<Person> getPersons() {
return persons;
}
}
场景 2 - Person
是可变的
您需要在 persons
方法中创建 getPersons
的深拷贝。
您需要在构造函数上创建 persons
的深拷贝。
您还需要将 final
设为类或至少将方法设为 getPersons
,以确保没有人提供 getPersons
方法的可变覆盖版本。
public final class Employees {
private final List<Person> persons;
public Employees(List<Person> persons) {
persons = new ArrayList<>();
for (Person person : persons) {
persons.add(deepCopy(person)); // If clone is provided
// and creates a deep copy of person
}
}
public List<Person> getPersons() {
List<Person> temp = new ArrayList<>();
for (Person person : persons) {
temp.add(deepCopy(person)); // If clone is provided
// and creates a deep copy of person
}
return temp;
}
public Person deepCopy(Person person) {
Person copy = new Person();
// Provide a deep copy of person
...
return copy;
}
}
这部分答案是为了说明为什么传递给构造函数的 personsParameter
的非深拷贝可以创建 Employees
的可变版本:
List<Person> personsParameter = new ArrayList<>();
Person person = new Person();
person.setName("Pippo");
personsParameter.add(person);
Employees employees = new Employees(personsParameter);
// Prints Pippo
System.out.println(employees.getPersons().get(0).getName());
employees.getPersons().get(0).setName("newName");
// Prints again Pippo
System.out.println(employees.getPersons().get(0).getName());
// But modifiyng something reachable from the parameter
// used in the constructor
person.setName("Pluto");
// Now it prints Pluto, so employees has changed
System.out.println(employees.getPersons().get(0).getName());
关于java - 如何使用 LinkedList 作为实例字段来管理不可变类?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39913008/