Java 按类名访问静态列表变量值(只读静态列表)可以吗?
这是我的密码Java 按类名访问静态列表变量值(只读静态列表)可以吗?,java,static,Java,Static,这是我的密码 public class PropertyLoader { private Properties appProperties; /** * The instance. */ private static PropertyLoader inst = null; /** * Instantiates a new property data loader. */ private PropertyLoad
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
方法需要同步:它是一个单实例,因此许多线程可以同时访问同一个实例并调用它
有人能给我建议正确的方法吗?您的
getInstance()
方法中发生了大量竞争情况。如果多个线程同时调用getInstance()
,您将创建多个实例,并将它们依次分配给静态变量。考虑到您在这里所做的工作,这不会导致任何逻辑问题,但确实意味着您所做的工作超出了必要的范围
我建议您阅读一些关于单例模式的内容,为什么它不好,以及如何在Java中以安全的方式实现它
但简言之,不要使用单例模式,它被严重破坏,将使任何使用此对象的代码紧密耦合,并将抑制您执行任何类型的隔离测试的能力。您的
getInstance()
方法中发生了大量竞争情况。如果多个线程同时调用getInstance()
,您将创建多个实例,并将它们依次分配给静态变量。考虑到您在这里所做的工作,这不会导致任何逻辑问题,但确实意味着您所做的工作超出了必要的范围
我建议您阅读一些关于单例模式的内容,为什么它不好,以及如何在Java中以安全的方式实现它
但简而言之,不要使用单例模式,它被严重破坏,会使任何使用此对象的代码紧密耦合,并会抑制您执行任何类型的隔离测试的能力。一个更简单的解决方案,也是线程安全的,就是使用静态初始化来初始化静态字段
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);
}
}
一个更简单的解决方案也是线程安全的,就是使用静态初始化来初始化静态字段
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);
}
}
您可以使用以下解决方案
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);
}
}
您可以使用以下解决方案
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);
}
}
您的代码有几个问题: (a) 您确定需要惰性初始化吗?初始化的成本必须是显著的,并且资源从未被使用的可能性必须是非零的。另外:最好在程序启动时失败,而不是在资源首次被访问时的某个不确定时刻。这实际上取决于您的应用程序 (b) 实现延迟初始化的一种方法是使用正确版本的双重检查锁定(volatile关键字至关重要): 这篇wikipedia文章解释了为什么这是可行的(从Java5开始,但之前没有):
(c) 在大多数情况下,捕获异常并简单地记录它们是完全错误的。在您的情况下,getPropertyAPP不会返回任何属性。如果属性的存在被明确声明为可选,那么这可能是正常的 您的代码有几个问题: (a) 您确定需要惰性初始化吗?初始化的成本必须是显著的,并且资源从未被使用的可能性必须是非零的。另外:最好在程序启动时失败,而不是在资源首次被访问时的某个不确定时刻。这实际上取决于您的应用程序 (b) 实现延迟初始化的一种方法是使用正确版本的双重检查锁定(volatile关键字至关重要): 这篇wikipedia文章解释了为什么这是可行的(从Java5开始,但之前没有):
(c) 在大多数情况下,捕获异常并简单地记录它们是完全错误的。在您的情况下,getPropertyAPP不会返回任何属性。如果属性的存在被明确声明为可选,那么这可能是正常的 也许您可以为
属性
推荐一种替代单例
模式的方法。顺便说一句:这个模式并没有被打破——它在Java中的许多实现都被打破了。这里介绍的单例模式和知道单例在哪里的类被打破了——Eric Gamma甚至说它不应该出现在GoF的书中。我建议在应用程序启动时手动或使用DI框架实例化它,并在必要时注入它。是的,但我已经在同步环境中调用了get instance means on contextInitialized,所以仍然提供静态块初始化。我不确定getPropertyAPP方法是否存在竞争条件。感谢您的解释。也许您可以为属性
推荐一种替代单例
模式的方法。顺便说一句:这个模式并没有被打破——它在Java中的许多实现都被打破了。这里介绍的单例模式和知道单例在哪里的类被打破了——Eric Gamma甚至说它不应该出现在GoF的书中。我建议在应用程序启动时手动或使用DI框架实例化它,并在必要时注入它。是的,但我已经在同步环境中调用了get instance means on contextInitialized,所以仍然提供静态块初始化。我不确定getPropertyAPP方法是否存在竞争条件。谢谢你的解释。嘿,彼得,IOException肯定会导致应用程序崩溃?@MrWiggles,除非默认值是合理的。否则我会用断言器包装IOE。嘿,彼得,IOException肯定会导致应用程序崩溃?@MrWiggles,除非默认值是合理的。否则我会用断言错误来包装IOE