Java:复合对象的不变性

Java:复合对象的不变性,java,Java,假设我有一个定义如下的Employee类: class Employee { private final String id; private final String name; private final String dept; private final Address address; public Employee(String id, String name, String dept, Address address) { this.id =

假设我有一个定义如下的Employee类:

class Employee {
   private final String id;
   private final String name;
   private final String dept;
   private final Address address;

   public Employee(String id, String name, String dept, Address address) {
    this.id = id;
    this.name = name;
    this.dept = dept;
    this.address = address;
   }

  public String getId() {
    return id; 
  }

  public String getName() {
    return name; 
  }

  public String getDept() {
    return dept; 
  }

  public Address getAddress() {
    return address; 
  }
}

class Address {
  private String addrLine1;
  private String addrLine2;
  ...
}

在上面的代码中,如果Address对象可以用setter更改,Employee真的是不可变的吗?如果不是,我们是否应该克隆()Employee以返回原始Employee?..

如果它的状态是可变的,它不是不可变的如果返回的对象是可变的,则第一个对象引用数据也将更改


正如您所说,只需返回一个安全副本。

如果它的状态是可变的,它不是不可变的如果返回的对象是可变的,则第一个对象引用数据也将更改


正如您所说,只需返回一份安全副本。

如果您的
地址
类具有使其可变的setter,那么不,我会说
员工
不是不可变的,因为它包含的地址可以更改。

如果您的
地址
类具有使其可变的setter,那么不,我认为
Employee
不是不可变的,因为它包含的地址可以更改。

您需要克隆()可变对象,即address。克隆雇员没有帮助。

您需要克隆()可变对象,即地址。克隆Employee不会有帮助。

您应该确保在存储任何可变字段之前对其进行克隆,并在getter中返回时进行克隆。 在构造函数中:

    this.address = address.clone();
在你的getter中:

    return address.clone();

这样,除此Employee对象外,没有其他对象可以访问Address对象的位置。

您应该确保在存储任何可变字段之前对其进行克隆,并在getter中返回时对其进行克隆。 在构造函数中:

    this.address = address.clone();
在你的getter中:

    return address.clone();

通过这种方式,除了这个Employee对象之外,没有其他对象可以访问address对象的位置。

这取决于您在不变性中想要什么:如果您希望它意味着对象的整个图形不会改变,那么显然,拥有一个可变地址是无法实现这一点的

我想,你可以将这种“深”不变性称为“浅”不变性

提供一个
@ImmutableValue
注释(以及用于编译时检查代码的相关maven插件),以确保当您希望某些内容是深度不可变的时,它实际上是不可变的

免责声明:我是这个库的开发者


但是,我希望它对某些人有用。

这取决于你想要什么样的不变性:如果你想让它意味着对象的整个图形不会改变,那么显然,拥有一个可变地址是无法实现这一点的

我想,你可以将这种“深”不变性称为“浅”不变性

提供一个
@ImmutableValue
注释(以及用于编译时检查代码的相关maven插件),以确保当您希望某些内容是深度不可变的时,它实际上是不可变的

免责声明:我是这个库的开发者


但是,我希望它对某些人有用。

您的代码不正确。属性地址声明为字符串,但getter返回地址。顺便说一句,这不是你要问的问题。既然它们是你问题的关键,你为什么要以上帝的名义把二传者排除在引用的代码之外@GuillaumePolet:关于地址的事情很正确,但是底部的那一点显然是个问题吗?这里还有第二个问题,
员工
是子类的,所以即使
地址
不是,实例也可以变为可变的。@TJ抱歉,我不理解这个问题,因为在我看来,很明显,如果一个对象的属性是可变的,那么你的对象也是可变的。我保证不会再做了!你的代码不正确。属性地址声明为字符串,但getter返回地址。顺便说一句,这不是你要问的问题。既然它们是你问题的关键,你为什么要以上帝的名义把二传者排除在引用的代码之外@GuillaumePolet:关于地址的事情很正确,但是底部的那一点显然是个问题吗?这里还有第二个问题,
员工
是子类的,所以即使
地址
不是,实例也可以变为可变的。@TJ抱歉,我不理解这个问题,因为在我看来,很明显,如果一个对象的属性是可变的,那么你的对象也是可变的。我保证不会再做了!