java - 如何使用 LinkedList 作为实例字段来管理不可变类?

标签 java class field immutability

我有一个名为 Employees 的不可变类,如下所示:

public final class Employees {
    private final List<Person> persons;

    public Employees() {
        persons = new LinkedList<Person>();
    }

    public List<Person> getPersons() {
        return persons;
    }
}

如何保持这个类不可变?

我将字段 privatefinal 设为了,我没有提供 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/

相关文章:

html - 这个html代码有什么错误?

PHP 类/OOP : When to "reference" a class within a class vs extend a class?

PHP:使用 Eclipse PDT 字段的类型提示

Java:从 Apache Tiles 2 2.2.2 迁移到 Tiles 3 3.0.5

java,设置-XX :HeapDumpPath directory to user.主页

java - 为什么使用Behavior渲染textField需要这么长时间

python - "The set of methods, however, is fixed when the class is first defined"是真的吗?

ruby-on-rails - collection_select类型字段上的必填字段

java - 类构造函数中的 ArrayList 字段

java - 按时间对一周中的几天进行排序