[英]Is this object mutable?
如果我有这样的课程:
public class MyObject {
private int myField = 2;
public void setMyField(int f) {
this.myField = f;
}
}
这类对象是否可变? 谢谢!
当然 - 如果你想要它是不可变的,那么你需要这样的东西:
public class MyObject {
private final int myField;
public MyObject(int f) {
myfield = f;
}
public int getMyField() {
return myField;
}
}
可变对象具有可以更改的字段,不可变对象没有可在创建对象后更改的字段。
您已经有几个答案并带有“ 是 ”。
我想添加一个“ 但是 ”(如果我会大胆,我会说“ 不 ”;-)
是的,这个类的对象看起来是可变的 ,因为它提供了一个更改字段的setter。 但是,由于它没有该字段的getter,也没有任何其他getter取决于该字段,并且由于该字段是私有的,因此目前无法读取该状态。
换句话说:对象具有状态,但它不会将任何状态暴露给外部。
我会称该对象为“有效不可变”。
存在一些设计模式,其中对象是“有效不可变的”,例如“不可变对象”的“延迟初始化”。
注意: Brian Goetz的“Java Concurrency in Practice”第3.5.4节讨论了“实际上不可变”的概念。
是的,这个类的对象是可变的。 该类的设计者不能通过任何技术手段(在现有的Java中)禁止对象的消费者观察和修改该领域的内容。
private是关于该字段的预期用途的明确声明的合同 - 该合同可以被破坏,例如通过反射。
在创建之后不提供任何改变对象数据的方法也可以是关于预期用途和可变性的(隐式声明的)合同 - 这个合同也可以被破坏,就像任何需要两个合规方的合同一样。
编辑:除非有另一方能够执行 - 例如在Java中,SecurityManager会阻止您在运行时更改最终字段。
是的 ,您的对象是可变的,因为在使用setter创建实例后,可以更改myField
的值。
使用final
字段可以实现不变性,因为一旦初始化变量,它将不允许您更改变量的值。
回答@JakubK指出如何使你的班级成为永恒。
但声明参考final
不会使对象被final
指向。
例如:
class MyObject{
private final List<Integer> list = new ArrayList<Integer>();
public List<Integer> getList(){
return list;
}
}
我可以通过做这样的事情来改变从外面向list
添加新元素
instance.getList().add(1); //mutates the list
此示例不是不可变的,因为List可以由其他人更改。
要定义某些东西是否可变,必须定义由此封装的状态。 如果MyObject
指定其状态包含Reflection将为myField
报告的值,则它是可变的。 如果该字段未被指定为对象的可观察状态的一部分,那么它可能被认为是不可变的大多数目的。
更具体地说,只有当一个类可以在类上,任何顺序和任何时间(甚至在多个线程上)执行任何记录操作的组合时,我认为类是不可变的,并且没有任何记录的行为方面的其中任何一个都受到其他任何影响。 当且仅当该更改会影响另一个方法调用的某些记录的行为方面(对于相同或不同的方法)时,方法可能更改私有字段的内容这一事实是相关的。 例如,我会说String.hashCode()
修改hash
字段的事实不会使String
变为可变,因为hashCode()
返回的值不受先前是否已写入字段的影响。 如果一个类有一个hashCode
方法,如果一个字段为空,则生成一个随机数并将其存储在该字段中,否则直接返回该值,这样的类将是可变的,除非它确保该字段已经过测试和设置作为原子操作。 在没有这种保证的情况下,几乎可以同时调用hashCode()
来产生不同的值,因此将来调用不同的值会与至少其中一个不同(意味着对象的状态已经改变)在返回奇数球值的呼叫和后面的呼叫之间)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.