This post讨论了可从最终字段传递的不可变对象:
不变性并不代表"不会改变"在Java中。这意味着"可以从最终字段传递到达,自最终字段设置以来没有改变,并且对包含最终字段的对象的引用没有逃脱构造函数"。
对于以下代码,
public class A() {
private String myString;
public A(String myString){
this.myString = myString;
}
public String getMyStringAndYours(){
return myString.concat("yours");
}
}
是可以从最终字段传递的实例吗?
我想是因为:
1。 myString.value
为final
2。 myString
可以myString.value
到达a
3。 A a.myString
的实例可以从a
附带问题:{{1}}是不可变的吗?
答案 0 :(得分:5)
我暂时搁置可传递的,并专注于final
和immutability
之间的区别。
class MyObject {
int a;
void setA(int val){
a=val;
}
}
final MyObject obj = new MyObject();
现在,由于obj 引用为final
,如果您尝试
obj = new MyObject(); // you can't re-initialize a final reference.
但你能做什么:
obj.setA(5); // perfectly valid.
您可以更改obj
引用的对象的状态,但无法将obj重新初始化为其他对象
现在,如果MyObject
内的所有字段都是final
且所有设置者都是私有(或缺席),那么将无法做到
obj.setA(5);
immutable
对象是其内部状态无法更改的对象。
现在,回到可传递的。如果由对象B和反过来对象B组成的对象A具有对象C(组合)。您的对象A不是真正的不可变,除非所有可传递的对象都是不可变的和 final ,即abc here a
,{ {1}}和b
应该是最终的,以防止重新分配对另一个对象的引用。此外,您应确保在创建时不共享c(避开A的范围)。如果它是共享的,那么任何其他对象都可以改变它。
编辑:
字符串不可变所以,你只需要将它们设为 final ,这样它们的封闭类就是 immutable 。
答案 1 :(得分:1)
A
"足够不可变"。因为在构造之后,字段myString
无法更改(至少在代码提供的上下文中),A
的状态不会更改,从而使其不可变。
此外,String#concat(String)不会更改String
的状态,如文档中所指定的,它会创建一个新的String,确保String是不可变的,并保持A
不可变的。
答案 2 :(得分:1)
您具有相反顺序的可达性。考虑这些类:
public class SomeBean {
private String a;
}
public class SomeOtherBean {
private SomeBean someBean;
...
}
public class Foo {
private final SomeOtherBean someOtherBean;
private /* non-final */ SomeOtherBean someOtherBean2;
}
然后Foo.someOtherBean.someBean
和Foo.someOtherBean.someBean.a
可以从最终字段传递,因为Foo.someOtherBean
是最终字段,而Foo.someOtherBean
,您可以Foo.someOtherBean.someBean
和Foo.someOtherBean.someBean.a
{1}} 按照参考资料。
另一方面,Foo.someOtherBean2.someBean
和Foo.someOtherBean2.someBean.a
不可以从最终字段传递,因为Foo.someOtherBean
不是最终字段。