创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
– 你已经有了 - 使所有的字段
private
和final
– 在您的代码进行适当的更改 - 不要提供任何改变实例状态的方法
- 如果你的类中有可变字段,比如
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
。
此外,我会使年龄是一个int
或double
而不是一个string。
您的示例已经是不可变的对象,因为Student类中的字段只能在实例初始化时设置。
要使对象不可变,您必须执行以下步骤:
- 不要使用任何可以改变你的class级的方法。 例如,不要使用Setters。
- 避免使用公开的非最终字段。 如果你的领域是公开的,那么你必须声明他们为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 { }
回答已经太迟了,但可能会帮助其他有这个问题的人。
- 不可变对象的状态在构造后不能被修改,任何修改都会导致新的不可变对象。
- 不可变类的所有字段应该是最终的。
- 对象必须正确构造,即对象引用在施工过程中不得泄漏。
- 对象应该是最终的,以限制子类改变父类的不变性。
我认为这个链接有助于了解更多: 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 }
- 将这个类声明为final,所以不能扩展。
- 将所有字段设为私有,以便不允许直接访问。
- 不要为variables提供setter方法
- 使所有可变字段最终,以便它的值只能分配一次。
- 通过执行深度复制的构造函数初始化所有的字段。
- 在getter方法中执行克隆对象以返回副本而不是返回实际的对象引用。
资源
有点扩大答案。
final
与Immutable
不一样,但如果以某种方式使用final
,则可以使用final
来使某些事情不可变。
某些types是不可改变的,因为它们代表不变的价值而不是可变状态的对象。 string,数字等是不可变的。 最后,通常我们的对象归结为最终引用不可变值的数据结构,但我们通过将新值赋给相同的字段名称来更改数据结构。
所以为了使一个真正不可变的东西,你需要确保最后一直使用,直到你到达每个字段到达你的构成树基础的每个值。 否则,可能会从你的对象下面改变出来,它并不是完全不可改变的。