【问题标题】:Objects in an immutable class as member variable不可变类中的对象作为成员变量
【发布时间】:2014-07-27 19:41:33
【问题描述】:

我有一个包含 Employee 对象的类 X。我想让 X 类成为不可变的。现在,即使我将 Employee 对象声明为 final,Employee 类也独立存在,人们可以访问该特定雇员对象的 setter 方法。是否可以有一个普通的 Employee 类和另一个持有 Employee 的不可变类 X,但是一旦分配了 Employee 的值我们就不能改变它?

public final class X {

private final Employee emp;

public X (Employee e){
   this.emp = e;

}
public Employee getEmp(){

return emp;

}

} 

我不想让它不可变的员工类,只是想让 X 类不可变。因此,一旦分配了员工,就不应该允许它改变它。 在不使 Employee 类不可变的情况下,这是否可能。 我希望 Employee 类独立存在,所以不想将其建设私有化。

【问题讨论】:

    标签: java immutability


    【解决方案1】:

    您不必公开不可变类的 Employee 成员。您可以引入仅公开 Employee 相关字段的 getter 方法。

    public final class X {
    
      private final Employee emp;
    
      public X (Employee e){
         this.emp = e.clone ();
      }
    
      public String getEmpName(){
        return emp.getName();
      }
    
      public int getEmpSalary(){
        return emp.getSalary();
      }
    
    } 
    

    当然,您还需要做一件事来确保该类确实是不可变的。构造函数应该创建传递给它的 Employee 的副本。否则,构造函数的调用者仍将拥有对 Employee 的引用,并且能够更改该对象。

    【讨论】:

    • 理论上其他人仍然可以更改通过构造函数提交的实例,因此这不是100%安全的解决方案
    • Hey Eran,现在一切都说得通了。谢谢(你的)信息。因此,如果我不返回带有 emp 对象的用户,他将无法进行任何修改。
    【解决方案2】:

    您可以向 Employee 添加一个复制构造函数,并在它的实例传入或传出不可变类时使用它。

    public final class X {
    
        private final Employee emp;
    
        public X (Employee e){
           this.emp = new Employee(e);
    
        }
        public Employee getEmp(){
          return new Employee(emp);
        } 
    } 
    

    话虽如此,您仍应认真重新评估是否更好地使 Employee 不可变,因为所有这些复制可能会产生相当大的开销。

    【讨论】:

    • 也感谢您提供此选项。我只是对这个设计感到好奇。如果我需要实施,它会记住你所说的。