这两个班级是一样的吗?
public class SingleTone {
// yes this is a bug what if i change the class this way
// private static SingleTone instance = new SingleTone();
// and empty constructor?
private static SingleTone instance;
private SingleTone() {
instance = new SingleTone();
}
public static SingleTone getInstance(){
return instance;
}
}
和
public class SingleTone {
private final static SingleTone instance = new SingleTone();
private SingleTone() {
}
public static SingleTone getInstance(){
return instance;
}
}
在构造函数实例化的最终变量中是否存在任何线程安全问题?
问题2:
之间的区别是什么
private final static SingleTone instance = new SingleTone();
private SingleTone() {
}
和此:
private final static SingleTone instance;
private SingleTone() {
instance = new SingleTone();
}
答案 0 :(得分:2)
Queston 1
你的第一个例子不起作用。
如果在创建该类型的对象之前进行此调用SingleTone.getInstance()
,它将返回null
第二个例子很好用
问题2
同样的情况,你在构造函数中实例化一个静态字段。这没有意义,因为你无法保证在访问静态字段之前已经调用了构造函数。
您可以这样做:
private final static SingleTone instance;
static {
instance = new SingleTone();
}
这将在首次加载类时实例化静态字段。
回答你的评论。
如果你这样做:
private static final SingleTone instance = new SingleTone();
这是线程安全的,好像第一个线程没有完成初始化类而另一个线程试图访问它,另一个线程将阻塞。
有关详细信息,请参阅此问题:Thread safety of static blocks in Java
答案 1 :(得分:0)
这两个选项实际上是相同的(但在两种情况下都缺少构造函数中的super()
调用)。
但是,实现单例是使用私有静态字段的Java往往被弃用。现在,我会使用枚举。
public enum Elvis {
INSTANCE;
private final String[] favoriteSongs =
{ "Hound Dog", "Heartbreak Hotel" };
public void printFavorites() {
System.out.println(Arrays.toString(favoriteSongs));
}
}
如果您想进一步阅读:http://www.drdobbs.com/jvm/creating-and-destroying-java-objects-par/208403883?pgno=3
答案 2 :(得分:0)
SingleTone类必须返回一个引用,所以第一个例子是完全错误的。
考虑以下过程: 1.类加载由JVM启动 2.类被加载到JVM中。 3.构造函数执行 4.完成对象创建
public class SingleTone { 对于此示例,实例将在1和2之间存活 private final static SingleTone instance = new SingleTone();
private SingleTone() {
}
public static SingleTone getInstance(){
return instance;
}
}
public class SingleTone { 对于此示例,实例将在3到4之间存活 private final static SingleTone实例;
private SingleTone() {
instance = new SingleTone();
}
public static SingleTone getInstance(){
return instance;
}
}