可以通过类名访问静态列表变量值,这是一个只读静态列表吗?

时间:2014-12-26 13:18:46

标签: java static

这是我的代码。

public class PropertyLoader {

    private Properties appProperties;

    /**
     * The instance.
     */
    private static PropertyLoader inst = null;

    /**
     * Instantiates a new property data loader.
     */
    private PropertyLoader() {
        try
        {
            appProperties = new Properties();
            appProperties.load(this.getClass().getClassLoader().getResourceAsStream("app.properties"));
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }
    }

    public static PropertyLoader getInstance() {
        if (inst == null) {
            inst = new PropertyLoader();
        }
            return inst;
        }
    }

    public String getPropertyAPP(String key) {
        return appProperties.getProperty(key);
    }

}

getPropertyAPP方法需要同步:它是一个单例,因此许多线程可以同时访问同一个实例并调用它。

有人能以正确的方式向我推荐吗?

4 个答案:

答案 0 :(得分:3)

您可以使用以下解决方案

public class PropertyLoader {

        private Properties appProperties;

    /** The instance. */
    private static PropertyLoader inst = null;

    static{
        inst = new PropertyLoader();
    }

    /**
     * Instantiates a new property data loader.
     */
    private PropertyLoader() {
            try
            {
                appProperties = new Properties();
                appProperties.load(this.getClass().getClassLoader().getResourceAsStream("app.properties"));
            }
            catch(IOException e)
            {
                e.printStackTrace();
            }
    }

    public static PropertyLoader getInstance() {
        return inst;
    }


    public String getPropertyAPP(String key) {
        return appProperties.getProperty(key);
    }
}

答案 1 :(得分:1)

一个更简单的解决方案,也是线程安全的,是使用静态初始化来初始化静态字段。

public class AppProperties {
    private static final Properties appProperties;
    static {
        try {
            appProperties = new Properties();
            appProperties.load(AppProperties.class
                      .getClassLoader().getResourceAsStream("app.properties"));
        } catch(IOException e) {
            e.printStackTrace();
        }
    }

    public String get(String key) {
        return appProperties.getProperty(key);
    }

    public String get(String key, String defaultValue) {
        return appProperties.getProperty(key, defaultValue);
    }
}

答案 2 :(得分:0)

您的getInstance()方法中发生了大规模的竞争状况。如果多个线程同时调用getInstance(),您将创建多个实例并将它们依次分配给静态变量。考虑到你在这里所做的事情,这不会导致任何逻辑问题,但这意味着你做的工作超出了必要的范围。

我建议你做一些关于Singleton模式的阅读,为什么它不好,以及如何在Java中以安全的方式实现它。

但简而言之,不要使用Singleton模式,它会被严重破坏,并且会使使用此对象的任何代码紧密耦合,并且会阻碍您进行任何类型的隔离测试。

答案 3 :(得分:0)

您的代码有几个问题:

(a)您确定需要延迟初始化吗?初始化的成本必须是显着的,并且从不使用资源的机会必须是非零的。另外:最好在程序启动期间失败,而不是在首次访问资源时的某个不确定时刻失败。这实际上取决于您的应用程序。

(b)实现延迟初始化的一种方法是使用正确版本的双重检查锁定(volatile关键字是必不可少的):

private static volatile PropertyLoader inst;
...
public static PropertyLoader getInstance() {
    if (inst == null) {
        synchronized(PropertyLoader.class) {
            if (inst == null) {
                inst = new PropertyLoader();
            }
        }
    }
    return inst;
} 

这篇维基百科文章解释了为什么这样有效(从Java 5开始,但之前没有):http://en.wikipedia.org/wiki/Double-checked_locking

(c)在大多数情况下捕获异常并简单地记录它们是完全错误的。在您的情况下,getPropertyAPP不会返回任何属性。如果明确声明属性的存在是可选的,则可能没问题。