Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/string/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在Java中创建用户定义的不可变类,该类将用户定义的类对象作为类成员?_Java_String_Immutability - Fatal编程技术网

如何在Java中创建用户定义的不可变类,该类将用户定义的类对象作为类成员?

如何在Java中创建用户定义的不可变类,该类将用户定义的类对象作为类成员?,java,string,immutability,Java,String,Immutability,我想创建包含Employee对象的不可变类EmployeeDetails。我遵循了使类不可变的条件: 1.课程是期末考试 2.班级成员是最终的 3.无二传手 如果EmployeeDetails是不可变的,我就不能更改其中的内容。不过,我可以更改员工姓名或id 我错过了什么 public class TestImmutable{ public static void main(String args[]){ EmployeeDetails empd1 = new Emplo

我想创建包含Employee对象的不可变类EmployeeDetails。我遵循了使类不可变的条件: 1.课程是期末考试 2.班级成员是最终的 3.无二传手

如果EmployeeDetails是不可变的,我就不能更改其中的内容。不过,我可以更改员工姓名或id

我错过了什么

public class TestImmutable{
    public static void main(String args[]){
        EmployeeDetails empd1 = new EmployeeDetails("ABC", new Employee(1, "n1"));

        System.out.println("Id   : " + empd1.getEmployee().getId());
        System.out.println("Name : " + empd1.getEmployee().getName());
        System.out.println("Empr : " + empd1.getEmployer());

        empd1.getEmployee().setId(2);
        empd1.getEmployee().setName("n2");
        System.out.println("\nId   : " + empd1.getEmployee().getId());
        System.out.println("Name : " + empd1.getEmployee().getName());
        System.out.println("Empr : " + empd1.getEmployer());
    }
}

final class EmployeeDetails{
    private final String employer;
    private final Employee emp1;

    public EmployeeDetails(String employer, Employee emp1){
        this.employer = employer;
        this.emp1 = emp1;
    }

    public String getEmployer(){
        return this.employer;
    }

    public Employee getEmployee(){
        return this.emp1;
    }
}

class Employee{
    public int id;
    public String name;

    public Employee(int id, String name){
        this.id = id;
        this.name = name;
    }

    public int getId(){
        return this.id;
    }

    public String getName(){
        return this.name;
    }

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

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

摆脱
getEmployee()
。您应该无法访问
员工emp1
外部
员工详细信息
。如果需要访问
Employee emp1
中的字段,请提供返回这些字段的公共方法

例如:

final class EmployeeDetails{
    private final String employer;
    private final Employee emp1;

    public EmployeeDetails(String employer, Employee emp1){
        this.employer = employer;
        this.emp1 = emp1;
    }

    public String getEmployer(){
        return this.employer;
    }

    public String getEmployeeName() {
        return this.emp1.getName();
    }

    ...
}

将变量设为final意味着您不能再次将其分配给其他对象。您仍然可以修改其引用所在对象的状态

在这种情况下:

final class EmployeeDetails{
  private final String employer;
  **private final Employee emp1;**
}
不能将emp1分配给新对象,但仍然可以更改employee对象的状态,因为它不是不可变的。通过删除所有setter,可以使Employee对象不可变

我遵循了使类不可变的条件:1。课程是期末考试 2.班级成员是最后三名。无二传手

您设置的条件是必要的,但不足以使类不可变。困惑

不变性是指始终保持类实例的状态。一旦创建了类的实例,那么构成该实例状态的所有属性都必须永远保持不变

如果满足上面的1到3,但其中一个实例字段是可变类,会发生什么情况?在这种情况下,将对该实例字段的引用返回给客户机可以使客户机改变假定不可变类的状态

一种解决方案是对不可变类的所有实例字段执行防御性复制,这些字段本身是可变的。而不是

public Employee getEmployee(){
    return this.emp1;
}
更改此代码,以便将
Employee
对象的新副本返回给客户端。这可确保客户端无法获取对不可变类实例的内部状态的引用:

public Employee getEmployee(){
    return this.emp1.clone();  // this solution assumes that Employee
                               // is safely cloneable, which requires some
                               // care on your part.  An alternative is
                               // to define a copy constructor in the
                               // Employee class and: return new Employee(emp1);
}

防御性复制对于不可变类的所有可变组件都是必要的,并且在构建和字段访问期间必须应用此规则。否则,客户端代码就可以保留对类的可变内部状态的引用。

类的
EmployeeDetails
并不是不可变的。除了一条规则外,您已经遵循了不变性的一般规则。在Joshua Bloch的《有效Java》中,这条规则如下所述:

确保以独占方式访问任何可变组件

在您的例子中,由于类
Employee
是可变的,因此需要在getter和构造函数中复制
Employee
实例

public Employee getEmployee() {
    return new Employee(emp1.getId(), empl.getName());       // Copy
}

public EmployeeDetails(String employer, Employee emp1){
    this.employer = employer;
    this.emp1 = new Employee(emp1.getId(), empl.getName());  // Copy
}
由于此版本使用副本,因此无法修改
EmployeeDetails
类的内部内容

这种解决方案非常常见。例如,
String
类是不可变的。构造函数
String(char[]value)
和方法
char[]tocharray()
都会复制数组。这是必要的,因为数组是可变的

另一种可能更适合您的情况的解决方案是使
Employee
也不可变


您甚至可以完全取消
Employee
类,只需在
EmployeeDetails
类中使用两个字段。

这些条件都不是严格必需的。这是真的。对这些条件最准确的描述是,它们既不是类不可变的必要条件,也不是不可变的充分条件。我应该考虑的另一个条件是对任何可变组件的独占访问。