Java 使纯不可变类

Java 使纯不可变类,java,Java,我有以下课程: Emp.java final public class Emp { private Integer id; private String name; private Department department; public Emp(Integer id, String name, Department department) { this.id = id; this.name = name; t

我有以下课程:

Emp.java

final public class Emp {

    private Integer id;
    private String name;
    private Department department;

    public Emp(Integer id, String name, Department department) {
        this.id = id;
        this.name = name;
        this.department = department;
    }

    public Department getDepartment() {
        return department;
    }

    public Integer getId() {
        return id;
    }

    public String getName() {
        return name;
    }
}
public class Department {

    private Integer id;
    private String name;

    public Department(Integer id, String name) {
        this.id = id;
        this.name = name;
    }

    public Integer getId() {
        return id;
    }

    public String getName() {
        return name;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public void setName(String name) {
        this.name = name;
    }
}
public class EmployeeTest {

    public static void main(String args[]) {
        Department dept1 = new Department(1, "dept1");
        Emp emp = new Emp(1, "emp1", dept1);
        emp.getDepartment().setName("dept2");
        System.out.println("emp = "+emp);

    }
}
Department.java

final public class Emp {

    private Integer id;
    private String name;
    private Department department;

    public Emp(Integer id, String name, Department department) {
        this.id = id;
        this.name = name;
        this.department = department;
    }

    public Department getDepartment() {
        return department;
    }

    public Integer getId() {
        return id;
    }

    public String getName() {
        return name;
    }
}
public class Department {

    private Integer id;
    private String name;

    public Department(Integer id, String name) {
        this.id = id;
        this.name = name;
    }

    public Integer getId() {
        return id;
    }

    public String getName() {
        return name;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public void setName(String name) {
        this.name = name;
    }
}
public class EmployeeTest {

    public static void main(String args[]) {
        Department dept1 = new Department(1, "dept1");
        Emp emp = new Emp(1, "emp1", dept1);
        emp.getDepartment().setName("dept2");
        System.out.println("emp = "+emp);

    }
}
EmployeeTest.java

final public class Emp {

    private Integer id;
    private String name;
    private Department department;

    public Emp(Integer id, String name, Department department) {
        this.id = id;
        this.name = name;
        this.department = department;
    }

    public Department getDepartment() {
        return department;
    }

    public Integer getId() {
        return id;
    }

    public String getName() {
        return name;
    }
}
public class Department {

    private Integer id;
    private String name;

    public Department(Integer id, String name) {
        this.id = id;
        this.name = name;
    }

    public Integer getId() {
        return id;
    }

    public String getName() {
        return name;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public void setName(String name) {
        this.name = name;
    }
}
public class EmployeeTest {

    public static void main(String args[]) {
        Department dept1 = new Department(1, "dept1");
        Emp emp = new Emp(1, "emp1", dept1);
        emp.getDepartment().setName("dept2");
        System.out.println("emp = "+emp);

    }
}
在这里,Emp类并不是一个完全不变的类,因为我能够以某种方式更改Department的值(如示例所示)


使Emp成为纯不可变类的最佳更改是什么?

使所有属性成为最终属性,并删除所有设置器使所有属性成为最终属性,并删除所有设置器实现克隆()在部门中创建Emp并在getDepartment()中返回部门的克隆

如果在构建Emp时使用的部门引用在构建后可用,则Emp的构造函数应克隆给定的部门。

在部门中实现克隆(),并在getDepartment()中使Emp返回部门的克隆


如果在构造Emp时使用的部门引用在构造后可用,则Emp的构造函数应克隆给定的部门。

getters中,对于非原语字段,使用此结构

public class Line {

   private final Point start;
   private final Point end;

   public Line(final Point start, final Point end) {
       this.start = new Point(start);
       this.end = new Point(end);
   }

   public Point getStart() {
       return new Point(start);
   }

   public Point getEnd() {
       return new Point(end);
   }
}  
所以,只需创建一个新的department实例,该实例等于上一个department实例

另外,在我的示例中,您可以看到纯不可变类
编辑:
也可以添加到Department类副本构造函数

public Department(final Department dep)  
{ ... } 
和雇主

getDepartment()  
{  
   return new Department(department);  
}

在非原语字段的getters中,使用此结构

public class Line {

   private final Point start;
   private final Point end;

   public Line(final Point start, final Point end) {
       this.start = new Point(start);
       this.end = new Point(end);
   }

   public Point getStart() {
       return new Point(start);
   }

   public Point getEnd() {
       return new Point(end);
   }
}  
所以,只需创建一个新的department实例,该实例等于上一个department实例

另外,在我的示例中,您可以看到纯不可变类
编辑:
也可以添加到Department类副本构造函数

public Department(final Department dep)  
{ ... } 
和雇主

getDepartment()  
{  
   return new Department(department);  
}

如果您不喜欢删除setter并在构造函数中进行初始化,那么可以考虑返回不可变(从
Emp
class的角度)对象,它将在getter中创建web对象的副本(请参阅)

当然,在
部门
中实现方法
clone()
(这将实现接口
Cloneable


如果您需要能够修改
Department
,但是
Emp
类的对象应该不会受到这些外部修改的影响,那么这种方法是合适的。

如果您不喜欢删除setter并在构造函数中进行初始化,您可以考虑返回immutable(从
Emp
class)对象的角度来看,它将在getter中创建web对象的副本(请参阅)

当然,在
部门
中实现方法
clone()
(这将实现接口
Cloneable

如果您需要能够修改
Department
,但
Emp
类的对象应该不会受到这些外部修改的影响,那么这种方法是合适的。

请参阅effective Java:

第15项:最小化易变性–要遵循的5条规则

  • 不要提供任何修改对象状态的方法
  • 确保该类不能被扩展
  • 使所有字段成为最终字段
  • 将所有字段设置为私有
  • 确保对任何可变组件的独占访问
  • 请参见Effective Java:

    第15项:最小化易变性–要遵循的5条规则

  • 不要提供任何修改对象状态的方法
  • 确保该类不能被扩展
  • 使所有字段成为最终字段
  • 将所有字段设置为私有
  • 确保对任何可变组件的独占访问


  • 为什么你需要部门中的设置者?部门类可能也可以在其他地方使用…我的意图是使Emp类完全不可变,而不是部门。你需要的技术称为防御性复制。谷歌随时可供你使用。为什么你需要部门中的设置者?我可能会有这样的机会nt类也可以在其他地方使用…我的意图是使Emp类完全不可变,而不是部门。你需要的技术叫做防御复制。谷歌由你支配。@Ilya我没有注意到。这使我的答案不可用。@Ilya我没有注意到。这使我的答案不可用。这将使他的所有类不可变这不是他的本意。
    部门
    应该是可变的。这将使他的所有类都不可变,这不是他的本意。
    部门
    应该是可变的。
    部门
    仍然可以在代码中更改。您还必须在构造函数中进行复制/克隆。@maba是的,但现在是
    Emp
    >类是安全的,没有人可以通过改变
    department
    (我会更正我的答案)来破坏它的逻辑。但是如果我有一个
    dep
    department
    的引用,并在构造函数中使用它,那么我可以通过执行
    dep.setName(“其他”)来更新
    department
    并更改了
    部门
    @maba,在这种情况下,可以在构造函数中再次使用副本。对不起,忘记在代码中输入。在代码中仍然可以更改
    部门
    。@maba是的,但是现在
    Emp
    类是安全的,没有人可以破坏它它的逻辑是通过改变
    部门
    (我会更正我的答案。)但是如果我有一个
    dep
    部门
    的引用,并在构造函数中使用它,那么我可以通过执行
    dep.setName(“其他”)来更新
    部门
    并更改了
    部门
    @maba,在这种情况下,可以再次使用副本-在构造函数中。对不起,忘记输入代码。