在Java单例中使用static?

时间:2010-09-24 19:25:01

标签: java android static singleton

我正在使用Java for Android构建单例服务:

final class MyService {

    private static Context context = null;
    // ...

    private MyService() {
        myObj = new MyObj(context);
            // ...  
    }                       
    private static class Singleton {
        private static final MyService INSTANCE = new MyService();
    }

    /**
     *  a singleton - do not use new(), use getInstance().
     */
    static synchronized myService getInstance(Context c) {
        if (context == null) context = c;
        return Singleton.INSTANCE;
    }

为了提高性能,我始终使用静态变量和方法。

我的问题:

  • 对象,new()确保 初始化该对象的机会 在使用之前。有没有 相当于一个静态类?对于 示例:静态方法依赖时 在早期初始化 - 如此 就像上面的“背景”一样 - 是有的 一种确保的方法 初始化首先发生?我必须吗 如果没有,会抛出异常吗?

  • 因为这是静态的我期待的 只有班级本身:是 根据定义,单身?是 上面推荐的代码就是 防止实例化的方法 对象

提前致谢!

4 个答案:

答案 0 :(得分:2)

这当然是创建单身人士的一种方式。我想你可以取消静态助手;因性能原因而静态实际上并没有节省太多,而且会使代码混淆。

我认为你真正的问题是,在context不为空之前,是否可以延迟构造静态。答案取决于VM;在大多数“vanilla”Java VM中,INSTANCE实际上不会在第一次调用GetInstance()之前进行实例化。静态评估静态以获得更好的启动性能。这意味着只要context在第一次调用GetInstance()之前获得了其他内容,就会很好。

但是,请原谅我,但我不知道Android VM中的这种行为是否有所不同,Android VM在技术上不是“真正的”Java VM(Sun / Oracle也是如此)。为了安全起见,如果context在静态构造函数被调用时没有实例,我会在实例化之前使用静态工厂方法或简单的IoC来解析静态构造函数中的一个实例。 INSTANCE

答案 1 :(得分:1)

您可以向班级添加静态初始化块

public class MySingleton {
    /* Default constructor */
    private MySingleton() {
    }

    static {
          //Static init stuff...
        }
        ...
    }
}

静态初始化程序块将为每个加载类的类加载器调用一次 - 通常在进程的生命周期内只调用一次。

最后,根据定义,您的单例只会被创建一次,因此使用静态助手来完成工作不会带来性能上的好处。

答案 2 :(得分:0)

代码中存在缺陷。如果您使用其他 getInstance()第二次致电Context,该怎么办?您将获得一个使用错误上下文创建的实例,即第一次传入的实例。我不确定这是否是故意的,但这至少没有任何意义,它可能导致混乱和讨厌的错误。

如果目的是为每个特定的上下文返回相同的实例,我会使用以下内容:

public class Service {
    private static final Map<Context, Service> services = new HashMap<Context, Service>();
    private Context context;

    private Service(Context context) {
        this.context = context;
    }

    public static synchronized Service getInstance(Context context) {
        Service service = services.get(context);
        if (service == null) {
            service = new Service(context);
            services.put(context, service);
        }
        return service;
    }
}

这称为Multiton。它是FactoryFlyweight的组合。 synchronized修饰符在广泛使用时非常昂贵,您可以考虑使用ReentrantReadWriteLock。维基百科文章包含一个例子。

回到单身人士的故事,维基百科有several good examples。一个在类加载期间构造单例的基本元素,另一个在第一个请求时构造单例的元素。但一般来说,不鼓励使用这种模式。

答案 3 :(得分:0)

避免过度设计。请改用enum

  

虽然这种方法尚未被广泛采用,但是单元素枚举类型是实现单例的最佳方法。

     

Joshua Bloch

Joshua Bloch在this post中对此方法进行了解释。