Java 按需初始化持有人习语的正确实现
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/21604243/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Correct implementation of initialization-on-demand holder idiom
提问by chain ro
I have got two versions of "Initialization-on-demand holder idiom":
我有两个版本的“按需初始化持有人习语”:
- http://en.wikipedia.org/wiki/Initialization-on-demand_holder_idiom
- http://en.wikipedia.org/wiki/Singleton_pattern#The_solution_of_Bill_Pugh
- http://en.wikipedia.org/wiki/Initialization-on-demand_holder_idiom
- http://en.wikipedia.org/wiki/Singleton_pattern#The_solution_of_Bill_Pugh
The major difference between above is that the first one declared INSTANCE
as private, but the second one declared INSTANCE
as public.
上面的主要区别在于第一个声明INSTANCE
为private,而第二个声明INSTANCE
为public。
Please tell me which one should I use.
请告诉我应该使用哪一种。
Sorry, I have not found the difference between using privateand publicin my application:
抱歉,我没有发现在我的应用程序中使用private和public之间的区别:
public class Singleton {
private int x;
public int getX() {
return x;
}
private Singleton () {}
private static class LazyHolder {
//both private and public works
private static final Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance() {
return LazyHolder.INSTANCE;
}
}
The only thing I do is to call something like Singleton.getInsance().getX()
, so both versions works.
Thus I want to know the situations for using them.
我唯一要做的就是调用类似的东西Singleton.getInsance().getX()
,所以两个版本都可以使用。因此我想知道使用它们的情况。
采纳答案by Seelenvirtuose
There are several things to explain about singletons and the initialization-on-demand holder idiom. Here we go:
关于单身人士和按需初始化持有人习惯用法,有几件事需要解释。开始了:
1) The access modifier:
1)访问修饰符:
Normally you can't access fields and methods in another class if they are private. They must at least be package private (having no modifier, it is) if the accessing class is in the same package. So the correct way to implement it, would be:
通常你不能访问另一个类中的字段和方法,如果它们是私有的。如果访问类在同一个包中,它们至少必须是包私有的(没有修饰符,它是)。因此,实现它的正确方法是:
public class Singleton {
...
private static class LazyHolder {
static final Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance() {
return LazyHolder.INSTANCE;
}
}
However, JLS 6.6.1explains:
但是,JLS 6.6.1解释了:
Otherwise, if the member or constructor is declared private, then access is permitted if and only if it occurs within the body of the top level class (§7.6) that encloses the declaration of the member or constructor.
否则,如果成员或构造函数被声明为私有,则当且仅当它发生在包含成员或构造函数声明的顶级类(第 7.6 节)的主体内时,才允许访问。
That means, declaring the field INSTANCE
as private still allows the access from inside the top level class Singleton
. But the compiler must do some tricks to get around the private modifier: It inserts package private methods for getting and setting such a field.
这意味着,将字段声明INSTANCE
为私有仍然允许从顶级类内部访问Singleton
。但是编译器必须做一些技巧来绕过私有修饰符:它插入包私有方法来获取和设置这样的字段。
In fact, it does not matter, which modifier you place on it. If it is public, it still cannot be accessed from other classes than Singleton
. However ... I think the package private access is the best. Making it public does not makes sense. Making it private forces the compiler to do some tricks. Making it package private reflects what you have: Access to a class member from another class.
实际上,您在其上放置哪个修饰符并不重要。如果它是公共的,除了Singleton
. 但是...我认为包私有访问是最好的。公开是没有意义的。将其设为私有会强制编译器做一些技巧。将其设置为私有反映了您所拥有的:从另一个类访问类成员。
2) How to implement a singleton:
2)如何实现单例:
If you ever want to consider serialization, the singleton implementation will get a bit difficult. Joshu Bloch wrote a great section in his book "Effective Java" about implementing singletons. At the end, he concluded to simply use an enum for this, as the Java enum specification provides every charecteristic that is needed in regards to singletons. Of course, that does not use the idiom anymore.
如果您想考虑序列化,单例实现将变得有点困难。Joshu Bloch 在他的“Effective Java”一书中写了一个关于实现单例的重要部分。最后,他得出结论,为此只使用枚举,因为 Java 枚举规范提供了与单例相关的所有特性。当然,那不再使用这个成语了。
3) Considering design:
3)考虑设计:
In most design decisions, singletons do not have their places anymore. In fact, it could indicate a design issue, if you must place a singleton into your program. Keep in mind: Singletons provide a global acessmechanism to some data or services. And this is not OOP.
在大多数设计决策中,单身人士不再占有一席之地。事实上,如果你必须在你的程序中放置一个单例,它可能表明一个设计问题。请记住:单例为某些数据或服务提供了全局访问机制。这不是面向对象编程。
回答by McDowell
private static class LazyHolder {
$VISIBILITY static final Singleton INSTANCE = new Singleton();
From a consumer's point of view it does not really matter if $VISIBILITY is public or private because the LazyHoldertype is private. The variable is only accessible via the static method in both cases.
从消费者的角度来看,$VISIBILITY 是公开的还是私有的并不重要,因为LazyHolder类型是私有的。在这两种情况下,变量只能通过静态方法访问。
回答by neildo
I use number 1 (private INSTANCE) because you generally try to use the narrowest scope as possible. But in this case since the Holder class is private it doesn't really matter. However, suppose someone later decided to make the Holder class public then number 2 could be problematic from an encapsulation perspective (callers could bypass the getInstance() method and access the static field directly).
我使用数字 1(私有实例),因为您通常会尝试尽可能使用最窄的范围。但在这种情况下,由于 Holder 类是私有的,所以并不重要。但是,假设后来有人决定将 Holder 类设为公开,那么从封装的角度来看,数字 2 可能会出现问题(调用者可以绕过 getInstance() 方法并直接访问静态字段)。