创build不可变的Java对象

我的目标是使一个Java对象不可变。 我有一个classStudent 。 我用下面的方式编码来实现不变性:

 public final class Student { private String name; private String age; public Student(String name, String age) { this.name = name; this.age = age; } public String getName() { return name; } public String getAge() { return age; } } 

我的问题是,什么是最好的方式来实现Student课的不变性?

你的课并不是一成不变的,严格说来,它只是有效的不可变的。 为了使它不可变,你需要使用final

 private final String name; private final String age; 

尽pipe差异可能看起来很微妙, 但它可以在multithreading环境中产生显着的差异 。 一个不可变的类本质上是线程安全的,一个有效的不可变类只有在安全发布的情况下才是线程安全的。

有几件事你必须考虑做一个不可变的类:

  • 让你的class级final – 你已经有了
  • 使所有的字段privatefinal – 在您的代码进行适当的更改
  • 不要提供任何改变实例状态的方法
  • 如果你的类中有可变字段,比如List或者Date ,那么使它们成为final不够的。 你应该从他们的getters返回一个防御副本,这样他们的状态就不会被调用方法所改变。

对于第四点,假设你的类中有一个Date字段,那么这个字段的getter应该看起来像这样:

 public Date getDate() { return new Date(this.date.getTime()); } 

当你的可变字段本身包含一些可变字段,并且可以包含一些其他可变字段时,制作一个防御副本可能会变得头痛。 在这种情况下,你需要迭代地复制每一个。 我们将这个可变字段的迭代副本命名为Deep Copy

自己实现深度复制可能会很麻烦。 但是,如果把这个问题分开,一旦你看到自己陷入了这样一个需要深度防御的副本,你就应该重新考虑你的阶级devise。

使用final关键字:

 private final String name; private final String age; 

这很好,但是我也会把这个领域做final

此外,我会使年龄是一个intdouble而不是一个string。

您的示例已经是不可变的对象,因为Student类中的字段只能在实例初始化时设置。

要使对象不可变,您必须执行以下步骤:

  1. 不要使用任何可以改变你的class级的方法。 例如,不要使用Setters。
  2. 避免使用公开的非最终字段。 如果你的领域是公开的,那么你必须声明他们为final,并在构造函数中或直接在声明行中进行初始化。

使variables私有,没有setter方法将适用于原始数据types。 如果我的课有任何对象的集合?

使任何类不可变的集合对象?

使用extends collection类编写自己的集合对象,并遵循私有variables和无setter方法。 或者返回你的集合对象的克隆对象。

 public final class Student { private StudentList names;//Which is extended from arraylist public Student() { names = DAO.getNamesList()//Which will return All Student names from Database its upto you how you want to implement. } public StudentList getStudentList(){ return names;//you need to implement your own methods in StudentList class to iterate your arraylist; or you can return Enumeration object. } public Enumeration getStudentNamesIterator( Enumeration e = Collections.enumeration(names); return e; } public class StudentList extends ArrayList { } 

回答已经太迟了,但可能会帮助其他有这个问题的人。

  1. 不可变对象的状态在构造后不能被修改,任何修改都会导致新的不可变对象。
  2. 不可变类的所有字段应该是最终的。
  3. 对象必须正确构造,即对象引用在施工过程中不得泄漏。
  4. 对象应该是最终的,以限制子类改变父类的不变性。

我认为这个链接有助于了解更多: http : //javarevisited.blogspot.com/2013/03/how-to-create-immutable-class-object-java-example-tutorial.html#ixzz40VDQDDL1

它已经是不可改变的 – 一旦你初始化了内容,你就不能改变内容,因为你还没有创buildsetter。 您可能会将最终关键字添加到variables中。

将所有variables设置为final并在设置某个字段时,使其像String那样使用新设置的值返回对新的Student对象的引用。

您可以按照此示例中显示的指导原则进行操作(首先inputgoogle): http : //www.javapractices.com/topic/TopicAction.do? Id= 29

下面是几条规则,它们有助于使Java在Java中不可变:1.不可变对象的状态在构造之后不能被修改,任何修改都会导致新的不可变对象。 2.不可变类的所有领域应该是最终的。 3.对象必须正确构造,即对象引用在施工过程中不得泄漏。 4.为了限制子类改变父类的不变性,对象应该是最终的。

例:

 public final class Contacts { private final String name; private final String mobile; public Contacts(String name, String mobile) { this.name = name; this.mobile = mobile; } public String getName(){ return name; } public String getMobile(){ return mobile; } 

}

请参阅此链接: http : //javarevisited.blogspot.in/2013/03/how-to-create-immutable-class-object-java-example-tutorial.html

使类或variables作为最终的是足够的

 Public final class constants { private final String name; private final String mobile; // code } 
  1. 将这个类声明为final,所以不能扩展。
  2. 将所有字段设为私有,以便不允许直接访问。
  3. 不要为variables提供setter方法
  4. 使所有可变字段最终,以便它的值只能分配一次。
  5. 通过执行深度复制的构造函数初始化所有的字段。
  6. 在getter方法中执行克隆对象以返回副本而不是返回实际的对象引用。

资源

有点扩大答案。

finalImmutable不一样,但如果以某种方式使用final ,则可以使用final来使某些事情不可变。

某些types是不可改变的,因为它们代表不变的价值而不是可变状态的对象。 string,数字等是不可变的。 最后,通常我们的对象归结为最终引用不可变值的数据结构,但我们通过将新值赋给相同的字段名称来更改数据结构。

所以为了使一个真正不可变的东西,你需要确保最后一直使用,直到你到达每个字段到达你的构成树基础的每个值。 否则,可能会从你的对象下面改变出来,它并不是完全不可改变的。