Java单例设计模式:问题
我最近接受了一次采访,他问我关于单例设计模式的问题,关于它们是如何实现的,我告诉他,使用静态变量和静态方法,我们可以实现单例设计模式 他似乎对答案半满意,但我想知道Java单例设计模式:问题,java,spring,design-patterns,singleton,Java,Spring,Design Patterns,Singleton,我最近接受了一次采访,他问我关于单例设计模式的问题,关于它们是如何实现的,我告诉他,使用静态变量和静态方法,我们可以实现单例设计模式 他似乎对答案半满意,但我想知道 我们可以用多少种不同的方法 实现单例设计模式 在爪哇 Singleton对象的范围是什么?它在JVM中实际是如何工作的?我知道我们总是会有一个Singleton对象的实例,但该对象的实际作用域是什么,是在JVM中还是如果JVM中有多个应用程序在运行,而不是JVM中每个上下文的作用域,我真的很困惑,无法给出令人满意的解释 最后,他问是
谢谢 Singleton通常是通过一个静态实例对象(
private SingletonType SingletonType.instance
)来实现的,该对象通过一个静态的SingletonType SingletonType.getInstance()
方法延迟实例化。使用单体有很多陷阱,事实上,许多人认为单体是设计反模式。考虑到有关Spring的问题,面试官可能不仅想了解单身人士,还想了解他们的陷阱,以及解决这些陷阱的方法,即依赖注入。您可能会发现页面上的视频特别有助于理解单例的缺陷以及DI如何解决这一问题。一个静态字段可以在一个JVM中多次出现-通过使用不同的类加载器,可以多次加载和初始化同一个类,但是每个类都是独立存在的,JVM将结果加载的类视为完全不同的类
我认为Java程序员不应该在意,除非他正在编写一些框架。“每个虚拟机一个”是一个足够好的答案。人们经常这样说,严格来说,他们说的是“每个类加载器一个”
每个集群可以有一个单例吗?这是一场概念游戏。我不希望面试官这样说
private Object readResolve() {
return instance;
}
有几种方法可以在Java中实现单例模式:
// private constructor, public static instance
// usage: Blah.INSTANCE.someMethod();
public class Blah {
public static final Blah INSTANCE = new Blah();
private Blah() {
}
// public methods
}
// private constructor, public instance method
// usage: Woo.getInstance().someMethod();
public class Woo {
private static final Woo INSTANCE = new Woo();
private Woo() {
}
public static Woo getInstance() {
return INSTANCE;
}
// public methods
}
// Java5+ single element enumeration (preferred approach)
// usage: Zing.INSTANCE.someMethod();
public enum Zing {
INSTANCE;
// public methods
}
给出上述示例,每个类加载器将有一个实例
关于在集群中使用单个实例……我不确定“使用”的定义是什么……采访者是否暗示在集群中创建了单个实例?我不确定这是否有意义
最后,在spring中定义一个非单例对象只需通过singleton=“false”属性即可 单例的作用域是它在类加载器树中的节点。它包含类加载器,任何子类加载器都可以看到单例 理解这个作用域的概念很重要,尤其是在具有复杂类加载器层次结构的应用程序服务器中 例如,如果在应用程序服务器的系统类路径上的jar文件中有一个库,并且该库使用了一个单例,那么对于部署到应用程序服务器中的每个“应用程序”,该单例(很可能)都是相同的。这可能是好事,也可能不是好事(取决于图书馆) 类加载器,IMHO,是Java和JVM中最重要的概念之一,单例就是其中之一,所以我认为Java程序员“关心”是很重要的 3:最后,他问是否可以使用带有集群的Singleton对象,并解释一下,当我们调用Bean Factory获取对象时,有没有办法让Spring不实现Singleton设计模式 如果没有技术背景,这个问题的第一部分很难回答。如果集群平台能够像调用本地对象一样对远程对象进行调用(例如,在引擎盖下使用RMI或IIOP的EJB可能),则可以这样做。例如,驻留JVM的单例对象可以是集群范围的单例对象的代理,该单例对象最初通过JNDI或其他方式定位/连接。但是集群范围的单例是一个潜在的瓶颈,因为对其中一个单例代理的每次调用都会导致对单个远程对象的(昂贵的)RPC 问题的第二部分是Springbean工厂可以配置不同的作用域。默认情况下是单例(作用域在webapp级别),但它们也可以是会话或请求作用域,或者应用程序可以定义自己的
public class SingletonObject
{
private SingletonObject()
{
// no code req'd
}
public static SingletonObject getSingletonObject()
{
if (ref == null)
// it's ok, we can call this constructor
ref = new SingletonObject();
return ref;
}
public Object clone()
throws CloneNotSupportedException
{
throw new CloneNotSupportedException();
// that'll teach 'em
}
private static SingletonObject ref;
}
public final class Singleton{
private static final Singleton instance = new Singleton();
public static Singleton getInstance(){
return instance;
}
public enum EnumSingleton {
INSTANCE;
}
public static void main(String args[]){
System.out.println("Singleton:"+Singleton.getInstance());
System.out.println("Enum.."+EnumSingleton.INSTANCE);
System.out.println("Lazy.."+LazySingleton.getInstance());
}
}
final class LazySingleton {
private LazySingleton() {}
public static LazySingleton getInstance() {
return LazyHolder.INSTANCE;
}
private static class LazyHolder {
private static final LazySingleton INSTANCE = new LazySingleton();
}
}
private Object readResolve() {
return instance;
}
class Foo{
// Initialized in first run
private static Foo INSTANCE = new Foo();
/**
* Private constructor prevents instantiation from outside
*/
private Foo() {}
public static Foo getInstance(){
return INSTANCE;
}
}
class Bar{
private static Bar instance;
/**
* Private constructor prevents instantiation from outside
*/
private Bar() {}
public static Bar getInstance(){
if (instance == null){
// initialized in first call of getInstance()
instance = new Bar();
}
return instance;
}
}
class Blaa{
/**
* Private constructor prevents instantiation from outside
*/
private Blaa() {}
/**
* BlaaHolder is loaded on the first execution of Blaa.getInstance()
* or the first access to SingletonHolder.INSTANCE, not before.
*/
private static class BlaaHolder{
public static Blaa INSTANCE = new Blaa();
}
public static Blaa getInstance(){
return BlaaHolder.INSTANCE;
}
}