假设我有一些类的引用,它是最终的:
public final Mycalss ref;
和MyClass有几个属性(不是最终属性)。现在,当我像这样构造MyClass对象时:
ref = new MyClass( some arguments);
这是否意味着其他线程可以安全地查看Myclass的内容,因为它是最终引用的?
答案 0 :(得分:4)
创建引用final
意味着一旦将对象分配给该引用,就不能将其他对象分配给该引用。
但即使引用声明为final
,您也可以更改同一对象的值。
喜欢:
public final Myclass ref;
ref = new Myclass();
//this is not allowed
ref = new MyClass(); //since you have already assigned an object to your final reference
//this is allowed
ref.setSomeProperty("abc"):
有关线程和最终的答案,请参阅@Erwin Bolwidt的答案。
答案 1 :(得分:2)
来自Java Language Specification section 17.5:
最终字段的使用模型很简单:设置最终字段 对于该对象的构造函数中的对象;并且不要写 引用正在另一个地方构建的对象 线程可以在对象的构造函数完成之前看到它。如果这 跟随,然后当另一个线程看到该对象时,那 线程将始终看到正确构造的版本 对象的最终字段。它还会看到任何对象的版本或 由最终字段引用的数组,这些字段至少是最新的 最后的字段是。
(我的重点补充)
这是JLS的“线程和锁定”部分17的一部分,其中Java Memory Model规范也是其中的一部分。
是的,你是对的。这是安全构建对象的正确方法。
答案 2 :(得分:1)
正如其他人所说final
意味着只能对此变量进行一次分配。但是,在多线程环境中,如果线程A在线程B发出assignemnt之前访问该对象,则线程A将看到null
。这意味着线程A可以看到变量的两个不同值。
此外,您应该记住Memory Consistency Errors - 即,一个线程对对象所做的更改可能对另一个线程不可见。我建议您阅读同步和volatile
关键字 - this is a good place to start。
答案 3 :(得分:0)
如果你想让所有类都看到一个类的实例,其属性是不可变的,你应该将属性声明为private,而不是创建任何setter,并使用Singleton模式(你可以在google上找到它,基本上你的类的构造函数是私有的,在你的类中你有一个静态的字段并且是你的类的唯一实例,你创建一个静态的getInstance()方法并返回当前实例和/或实例化它它是空的。
该课程将如下所示:
public class A {
private static A instance;
private A() {}
public static synchronized A getInstance() {
if (instance == null) {
instance = new A();
}
return instance;
}
}