nsf*_*n55 82
以下是不可变对象的硬性要求.
final
但该对象仍然是可变的.即private final Date imStillMutable
).你应该defensive copies
在这些情况下做出来.上课的final
原因非常微妙,经常被忽视.如果不是最终的人可以自由地扩展你的类,覆盖public
或protected
行为,添加可变属性,然后提供他们的子类作为替代.通过声明课程,final
您可以确保不会发生这种情况.
要查看运行中的问题,请考虑以下示例:
public class MyApp{
/**
* @param args
*/
public static void main(String[] args){
System.out.println("Hello World!");
OhNoMutable mutable = new OhNoMutable(1, 2);
ImSoImmutable immutable = mutable;
/*
* Ahhhh Prints out 3 just like I always wanted
* and I can rely on this super immutable class
* never changing. So its thread safe and perfect
*/
System.out.println(immutable.add());
/* Some sneak programmer changes a mutable field on the subclass */
mutable.field3=4;
/*
* Ahhh let me just print my immutable
* reference again because I can trust it
* so much.
*
*/
System.out.println(immutable.add());
/* Why is this buggy piece of crap printing 7 and not 3
It couldn't have changed its IMMUTABLE!!!!
*/
}
}
/* This class adheres to all the principles of
* good immutable classes. All the members are private final
* the add() method doesn't modify any state. This class is
* just a thing of beauty. Its only missing one thing
* I didn't declare the class final. Let the chaos ensue
*/
public class ImSoImmutable{
private final int field1;
private final int field2;
public ImSoImmutable(int field1, int field2){
this.field1 = field1;
this.field2 = field2;
}
public int add(){
return field1+field2;
}
}
/*
This class is the problem. The problem is the
overridden method add(). Because it uses a mutable
member it means that I can't guarantee that all instances
of ImSoImmutable are actually immutable.
*/
public class OhNoMutable extends ImSoImmutable{
public int field3 = 0;
public OhNoMutable(int field1, int field2){
super(field1, field2);
}
public int add(){
return super.add()+field3;
}
}
Run Code Online (Sandbox Code Playgroud)
在实践中,在依赖注入环境中遇到上述问题是很常见的.你没有明确地实例化事物,你给出的超类引用实际上可能是一个子类.
需要注意的是,要对不可变性做出硬性保证,你必须将该类标记为final
.这在Joshua Bloch的Effective Java中有详细介绍,并在Java内存模型的规范中明确引用.
Ale*_*yak 13
类不是不可变的,对象是.
不可变的意思是:初始化后我的公共可见状态不能改变.
字段不必声明为final,但它可以极大地帮助确保线程安全
如果你的类只有静态成员,那么这个类的对象是不可变的,因为你不能改变那个对象的状态(你可能无法创建它:))
小智 6
要使类在Java中不可变,您可以记下以下几点:
1.不要提供setter方法来修改类的任何实例变量的值.
2.将该类声明为"最终".这将阻止任何其他类扩展它,从而阻止覆盖任何可能修改实例变量值的方法.
3.将实例变量声明为private和final.
4.您还可以将类的构造函数声明为private,并在需要时添加工厂方法以创建类的实例.
这些要点应该有帮助!!
来自甲骨文站点,如何在 Java 中创建不可变对象。
\n\n\n\n\n
\n- 不要提供修改字段或字段引用的对象的“setter”方法\xe2\x80\x94 方法。
\n- 将所有字段设为最终字段和私有字段。
\n- 不允许子类重写方法。最简单的方法是将类声明为final。更复杂的方法是将构造函数设为私有并在工厂方法中构造实例。
\n- 如果实例字段包含对可变对象的引用,则不允许更改这些对象:
\n
\n I. 不提供修改可变对象的方法。
\n 二. 不要共享对可变对象的引用。切勿存储对传递给构造函数的外部可变对象的引用;如有必要,创建副本并存储对副本的引用。同样,必要时创建内部可变对象的副本,以避免在方法中返回原始对象。
不可变对象是创建后不会改变其内部状态的对象。它们在多线程应用程序中非常有用,因为它们可以在没有同步的情况下在线程之间共享。
1.不要添加任何setter方法
如果你正在构建一个不可变对象,它的内部状态永远不会改变。setter 方法的任务是更改字段的内部值,因此您无法添加它。
2. 将所有字段声明为 final 和 private
从类外部看不到私有字段,因此不能对其应用任何手动更改。
声明一个字段 final 将保证如果它引用一个原始值,如果它引用一个对象,则该值永远不会改变,如果它引用一个不能改变的引用。这不足以确保只有私有 final 字段的对象不可变。
3.如果一个字段是一个可变对象,为getter方法创建它的防御性副本
我们之前已经看到,定义一个字段 final 和 private 是不够的,因为它可以改变其内部状态。为了解决这个问题,我们需要创建该字段的防御副本,并在每次请求时返回该字段。
4. 如果传递给构造函数的可变对象必须分配给一个字段,则创建它的防御副本
如果您持有传递给构造函数的引用,则会发生同样的问题,因为可以更改它。因此,持有对传递给构造函数的对象的引用可以创建可变对象。为了解决这个问题,如果参数是可变对象,则有必要创建参数的防御副本。
请注意,如果字段是对不可变对象的引用,则无需在构造函数和 getter 方法中创建它的防御性副本,只需将该字段定义为 final 和 private 就足够了。
5. 不允许子类覆盖方法
如果子类覆盖一个方法,它可以返回可变字段的原始值而不是它的防御性副本。
如果你遵循这些简单的规则,你就可以在线程之间自由共享你的不可变对象,因为它们是线程安全的!
没有对与错,这只是取决于你喜欢什么。这仅取决于您的偏好以及您想要实现的目标(并且能够轻松地使用这两种方法而不会疏远一方或另一方的铁杆粉丝是某些语言所追求的圣杯)。
归档时间: |
|
查看次数: |
84509 次 |
最近记录: |