JAVA单例模式不起作用。

3

我对在使用单例类初始化/访问ArrayList的代码进行了增强/测试。

import java.util.ArrayList;

public class SingletonArrayList {

    private static SingletonArrayList mInstance;
    private static ArrayList<String> list = null;

    public static SingletonArrayList getInstance() {
        if (mInstance == null)
            mInstance = new SingletonArrayList();
        SingletonArrayList.list.add("a");
        SingletonArrayList.list.add("b");
        SingletonArrayList.list.add("c");
        return mInstance;
    }

    private SingletonArrayList() {
        list = new ArrayList<String>();
    }

    // retrieve array from anywhere
    public ArrayList<String> getArray() {
        return SingletonArrayList.list;
    }

}

然后我创建了一个测试类,在其中调用上述单例两次:

import java.util.ArrayList;

public class TestSingletonArrayList {

    public static void main(String[] args) {


        ArrayList<String> array = SingletonArrayList.getInstance().getArray();
        for (int i = 0; i < array.size(); i++) {
            System.out.println(array.get(i));
        }
        System.out.println("-----------");
        ArrayList<String> array2 = SingletonArrayList.getInstance().getArray();
        for (int i = 0; i < array2.size(); i++) {
            System.out.println(array2.get(i));
        }

    }

}

输出结果为:
a
b
c
-----------
a
b
c
a
b
c

这看起来非常奇怪。我期望单例类的第二次调用只会返回a,b,c而不是a,b,c,a,b,c。
出了什么问题?我期望只有a,b,c,因为这是一个单例。
谢谢,问候 马里奥

Java不是JS,请不要将其放入代码片段中。 - azro
你的添加语句不在条件块中... - AxelH
2
在多线程环境下,实现单例模式可能会遇到一些问题。请阅读此帖子以获取正确的单例模式实现方法。 - Scary Wombat
2个回答

8

将其更改如下:

public class SingletonArrayList {
    private static SingletonArrayList mInstance;
    private static ArrayList<String> list = null;

    public static SingletonArrayList getInstance() {
        if (mInstance == null) {
            mInstance = new SingletonArrayList();
            SingletonArrayList.list.add("a");
            SingletonArrayList.list.add("b");
            SingletonArrayList.list.add("c");
        }

        return mInstance;
    }

    private SingletonArrayList() {
        list = new ArrayList<String>();
    }

    // retrieve array from anywhere
    public ArrayList<String> getArray() {
        return SingletonArrayList.list;
    }

}

这里的问题是必须同时创建和初始化对象。在您的解决方案中,您仅创建了一次对象,并为每个调用单独添加项目。虽然它仍然只有一个实例,但您在getInstance的每个调用中都会向该单例实例添加元素,这与直觉相反。

2

使用您的代码,每次调用单例实例时(因为只有下一条指令引用if),您都会添加三个元素abc,因此在第一次调用时,您拥有abc,第二次调用时,您拥有abcabc

您只需要在创建实例时添加它们:

public static SingletonArrayList getInstance() {
    if (mInstance == null){
        mInstance = new SingletonArrayList();
        SingletonArrayList.list.add("a");
        SingletonArrayList.list.add("b");
        SingletonArrayList.list.add("c");
    }
    return mInstance;
}

另外,真正的单例模式是使用final类和final实例来防止被修改的,你的代码适合于懒加载初始化,但你对其进行了修改,因此真正的实现应该是:

  • final类
  • 私有构造函数
  • 静态final实例
public final class SingletonArrayList {

    private static final SingletonArrayList mInstance = new SingletonArrayList();
    private static ArrayList<String> list = null;

    public static SingletonArrayList getInstance() {
        return mInstance;
    }

    private SingletonArrayList() {
        list = new ArrayList<String>();
        SingletonArrayList.list.add("a");
        SingletonArrayList.list.add("b");
        SingletonArrayList.list.add("c");
    } 

}

3
这些语句应该移动到构造函数中。 - AxelH

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接