正确实现按需初始化持有人的习惯做法[英] Correct implementation of initialization-on-demand holder idiom

本文是小编为大家收集整理的关于正确实现按需初始化持有人的习惯做法的处理/解决方法,可以参考本文帮助大家快速定位并解决问题,中文翻译不准确的可切换到English标签页查看源文。

问题描述

我有两个版本的"初始化按需持有人成语":

  1. /a>
  2. /li>

上面的主要区别在于,第一个声明为INSTANCE为私有,但第二个声明为INSTANCE为 public .

请告诉我我应该使用哪一个.


对不起,我没有发现在我的应用程序中使用 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;
    }
}

我唯一要做的就是称呼Singleton.getInsance().getX()之类的东西,因此两个版本都可以. 因此,我想知道使用它们的情况.

推荐答案

关于单例和按需持有人的初始化有几件事要解释.我们去:

1)访问修饰符:

通常,如果它们是私有的,则无法访问其他类中的字段和方法.如果访问类位于同一软件包中,他们至少必须是私有包装(没有修饰符).因此,正确实施它的方法是:

public class Singleton {
    ...
    private static class LazyHolder {
        static final Singleton INSTANCE = new Singleton();
    }
    public static Singleton getInstance() {
        return LazyHolder.INSTANCE;
    }
}

然而, jls 6.6.6.1 说明:

否则,如果成员或构造函数被私有声明,则访问为 允许且仅当它发生在顶级级别的主体内(第7.6节) 这包含成员或构造函数的声明.

这意味着,将字段声明为私有,仍然允许从顶级级别Singleton内部访问.但是编译器必须做一些技巧才能绕过私人修饰符:它插入包装的私人方法来获取和设置这样的字段.

实际上,这并不重要,您将哪个修饰符放在它上.如果是公开的,则仍然无法从Singleton以外的其他类中访问.但是...我认为私人访问包是最好的.公开它没有意义.使私人强迫编译器进行一些技巧.使其包装私有反映您的所拥有的:从另一堂课中访问类成员.

2)如何实现单例:

如果您想考虑序列化,那么Singleton实施将变​​得有些困难.约书·布洛赫(Joshu Bloch)在他的《有效的爪哇》中写了一个很棒的部分,内容涉及实施单身人士.最后,他得出的结论是简单地为此使用枚举,因为Java枚举规范提供了有关单身人士所需的每种收费.当然,这不再使用这个成语.

3)考虑设计:

在大多数设计决策中,单身人士不再有自己的位置.实际上,如果您必须将单身人士放入程序中,则可能表明设计问题.请记住:单例为某些数据或服务提供A 全局ACESS 机制.这不是OOP.

其他推荐答案

private static class LazyHolder {
    $VISIBILITY static final Singleton INSTANCE = new Singleton();

从消费者的角度来看,无论$ lazyholder 类型是私人的,$可见性是公共还是私人的,这并不重要.该变量仅在两种情况下都可以通过静态方法访问.

其他推荐答案

我使用数字1(私有实例),因为您通常尝试尽可能使用最狭窄的范围.但是在这种情况下,由于持有人类是私有的,这并不重要.但是,假设某人后来决定公开持有人类,那么从封装角度来看,数字2可能是有问题的(呼叫者可以绕过getInstance()方法并直接访问静态字段).

本文地址:https://www.itbaoku.cn/post/627706.html

问题描述

I have got two versions of "Initialization-on-demand holder idiom":

  1. http://en.wikipedia.org/wiki/Initialization-on-demand_holder_idiom
  2. 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.

Please tell me which one should I use.


Sorry, I have not found the difference between using private and public in my application:

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.

推荐答案

There are several things to explain about singletons and the initialization-on-demand holder idiom. Here we go:

1) The access modifier:

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.1 explains:

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.

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.

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.

2) How to implement a singleton:

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.

3) Considering design:

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 acess mechanism to some data or services. And this is not OOP.

其他推荐答案

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 LazyHolder type is private. The variable is only accessible via the static method in both cases.

其他推荐答案

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).