单例实例化

时间:2011-08-19 11:59:58

标签: java singleton

下面显示的是单例对象的创建。

public class Map_en_US extends mapTree {

    private static Map_en_US m_instance;

    private Map_en_US() {}

    static{
        m_instance = new Map_en_US();
        m_instance.init();
    }

    public static Map_en_US getInstance(){
        return m_instance;
    }

    @Override
    protected void init() {
        //some code;
    }
}

我的问题是使用静态块进行实例化的原因是什么。我熟悉单身实例化的以下形式。

public static Map_en_US getInstance(){
    if(m_instance==null)
      m_instance = new Map_en_US();
}

10 个答案:

答案 0 :(得分:36)

答案 1 :(得分:1)

如果在getInstance()方法中初始化,则可以获得竞争条件,即如果2个线程同时执行if(m_instance == null)检查,则两者都可能看到实例为空,因此两者都可能调用{{ 1}}

由于静态初始化程序块只执行一次(由一个执行类加载器的线程执行),因此你没有问题。

Here's a good overview.

答案 2 :(得分:1)

这种消除静态块的方法如何:

private static Map_en_US s_instance = new Map_en_US() {{init();}};

它做同样的事情,但是更整洁。

此语法的说明:
外部括号组创建一个匿名类 内部支撑组称为“实例块” - 它在构造过程中会发生爆炸 这种语法通常被错误地称为“双括号初始化器”语法,通常是那些不了解发生了什么的人。

另外,请注意:
m_ instance (即成员)字段的命名约定前缀 s_ class (即静态)字段的命名约定前缀 所以我将字段的名称更改为s_...

答案 3 :(得分:0)

这取决于init方法的资源密集程度。如果它,例如做了很多工作,也许你希望在应用程序启动时完成工作而不是第一次调用。也许它从互联网下载地图?我不知道......

答案 4 :(得分:0)

当JVM首次加载类时,将执行静态块。正如Bruno所说,这对线程安全有帮助,因为两个线程不可能第一次在同一个getInstance()调用上进行争用。

答案 5 :(得分:0)

  1. 使用静态实例化,每个类只有一个实例副本,无论创建多少个对象。
  2. 方法的第二个优点是,方法是thread-safe,因为除了返回实例之外,你没有在方法中做任何事情。

答案 6 :(得分:0)

静态块实例化您的类并且只调用一次默认的构造函数(如果有的话)以及应用程序启动时所有静态元素都由JVM加载。

使用getInstance()方法,在调用方法时构建并初始化类的对象,而不是静态初始化。如果你同时在不同的线程中运行getInstance(),那就不安全了。

答案 7 :(得分:0)

静态块在此处允许init调用。其他编码方式可能就像这样(喜欢的是品味问题)

public class Map_en_US extends mapTree {

    private static
            /* thread safe without final,
               see VM spec 2nd ed 2.17.15 */
            Map_en_US m_instance = createAndInit();

    private Map_en_US() {}

    public static Map_en_US getInstance(){
        return m_instance;
    }

    @Override
    protected void init() {
        //some code;
    }

    private static Map_en_US createAndInit() {
        final Map_en_US tmp = new Map_en_US();
        tmp.init();
        return tmp;
    }
}

更新已修正每VM spec 2.17.5,评论中的详细信息

答案 8 :(得分:0)

    // Best way to implement the singleton class in java
    package com.vsspl.test1;

    class STest {

        private static STest ob= null;
        private  STest(){
            System.out.println("private constructor");
        }

        public static STest  create(){

            if(ob==null)
                ob = new STest();
            return ob;
        }

        public  Object  clone(){
            STest   obb = create();
            return obb;
        }
    }

    public class SingletonTest {
        public static void main(String[] args)  {
            STest  ob1 = STest.create();
            STest  ob2 = STest.create();
            STest  ob3 = STest.create();

            System.out.println("obj1  " +  ob1.hashCode());
            System.out.println("obj2  " +  ob2.hashCode());
            System.out.println("obj3  " +  ob3.hashCode());


            STest  ob4 = (STest) ob3.clone();
            STest  ob5 = (STest) ob2.clone();
            System.out.println("obj4  " +  ob4.hashCode());
            System.out.println("obj5  " +  ob5.hashCode());

        }
    }

-------------------------------- OUT PUT -------------------------------------
private constructor
obj1  1169863946
obj2  1169863946
obj3  1169863946
obj4  1169863946
obj5  1169863946

答案 9 :(得分:-1)

之前从未见过有趣的人。似乎主要是风格偏好。我认为一个区别是:静态初始化发生在VM启动时,而不是第一次请求实例,可能会消除并发实例化的问题? (也可以使用synchronized getInstance()方法声明处理)