不变性的定义表明,在构造之后,对象的状态(其数据)不能被改变。
这里提出了一个问题,在我看来,对象包含的状态和数据是不同的东西。 也许状态意味着通过getter提供的数据?
这并不意味着标记为私有且外部世界不可见的数据,这些数据确实可以改变而不会改变对象的状态。
告诉我这是否正确:
final class Obj1 {
private final int i;
private final Random rnd = new Random();
private int j = rnd.nextInt(1000);
public Obj1(int i) {
this.i = i;
}
public getI() {
j = rnd.nextInt(1000);
return i;
}
}
Obj1
的实例是一个不可变对象。
final class Obj2 {
private final int i;
private final Random rnd = new Random();
private int j = rnd.nextInt(1000);
public Obj1(int i) {
this.i = i;
}
public getI() {
return i;
}
public getJ() {
return j;
}
}
Obj2
的实例是一个可变或不可变的对象,为什么?如果每次调用getter时我们在getJ体中得到下一个Random会怎么样?
这样的课怎么样?可变/不可变,为什么?
final class Obj3 {
private final Random rnd = new Random();
private int j = rnd.nextInt(1000);
public Obj1() {
}
public getJ() {
return j;
}
}
这个怎么样?可变/不可变,为什么?
final class Obj4 {
private final Random rnd = new Random();
public Obj1() {
}
public getRnd() {
return rnd.nextInt(1000);
}
}
答案 0 :(得分:7)
关于不变性的一个重要观点是,对象的可观察状态不得改变。
一个非常好的例子是java.lang.String
,它经常被引用为不可变类的规范示例。它有一个非final
字段,即hash
。 hash
包含哈希码,但默认为0
。在第一次调用hashCode()
并在该字段中缓存时,会懒惰地计算哈希码。这样String
对象的内部状态可以改变,但可观察状态永远不会改变(因为hashCode()
总是返回相同的值,不无论是计算还是仅返回缓存值,都很重要。)
这意味着您提供的前三个示例(Obj1
,Obj2
,Obj3
)是不可变的:它们没有setter,其他任何东西都无法更改其方法返回的值构造(声明字段final
是个好主意,但它不是不可变性的要求)。另请注意,您也可以完全忽略这些类中的Random
字段,因为它在构建之后仍未使用。
我会说最后一个样本(Obj4
)肯定是可变的,因为每次从中读取时都会改变状态(即下一个getRnd()
调用返回的内容)(即每次你致电getRnd()
)。
所以,回答标题中的问题:是的,如果Random
对象的状态不可观察,引用Random
对象的类可以是不可变的在班级本身的状态。
答案 1 :(得分:0)
好问题。但这是术语的问题,而不变性更多的是关于如何使用对象。不可变对象的好处:
如果它在构造后改变状态,我不会将对象声明为不可变的,即使它必须是setter。
答案 2 :(得分:0)
如果引用被识别为标识而不是持有,则不可变对象保持甚至公开对任意类型对象的引用是完全合法的,有问题的对象。例如,将对象引用视为类似于VIN(车辆标识号 - 唯一标识车辆的字母数字字符串,至少是美国制造或进口的车辆),并想象维修车间可能保留一个它所服务的汽车的VIN列表。汽车本身很难成为不可改变的物品,但是列表不能存放汽车 - 它会识别汽车。人们无法看到VIN并且知道汽车在维修时的颜色是什么,但是当汽车进入商店时,可以使用VIN列表来确定汽车是否曾经访问过。