有没有更好的方法为外部类创建单例对象?我正在这样做,但是有更好的方法吗?
import com.amazonaws.auth.AWSCredentialsProvider;
import com.amazonaws.auth.DefaultAWSCredentialsProviderChain;
public class GetAWSCredentials {
private static AWSCredentialsProvider credentials;
public static synchronized AWSCredentialsProvider getInstance() {
if (credentials == null) {
credentials = new DefaultAWSCredentialsProviderChain();
}
return credentials;
}
}
在这种情况下,您的外部库类不是单例,因为首先它是一个接口。即使不是,任何人都可以从此类外部创建一个新实例。您无法将不是单例的外部类转变为一个。
现在,如果您想为自己的类 GetAWSCredentials 找到创建单例的最简洁方法,那么您可以尝试 effective-java 建议
是的,有。简单来说就是:
public class GetAwsCredentials {
private static final AwsCredentialsProvider credentials = new GetAwsCredentials();
public static AwsCredentialsProvider getInstance() {
return credentials;
}
}
您可能会想:哦不,那不行!我不希望在 JVM 启动时创建此实例,仅在需要时创建!
但是..这已经是java的工作原理了。直到需要时才会按原样加载类。在某种访问方法中创建实例实际上是没有意义的;只需在类负载上进行即可。在 99% 需要单例的情况下,如果你要提到相关的类,你很快就会调用
getInstance()
方法。
在极不可能的情况下,您确实需要这样做(并且如果该构造函数做了相当多的繁重工作,则这仅才算数),您可以使用此构造:
public class GetAwsCredentials {
private static class AwsCredentialsHolder {
static final AwsCredentialsProvider provider = new AwsCredentialsProvider();
}
public static AwsCredentialsProvider getInstance() {
return AwsCredentialsHolder.provider;
}
}
无需使用
volatile
或 synchronized
。也就是说:
synchronized
),要么试图减轻重量,例如使用双重检查锁定,“太轻” - 它们似乎可以工作,但在适当的负载下它们会失败(从某种意义上说,您最终会得到2个实例)。static final
字段,我们可以搭载它,这是该 java 提供的最有效的机制。.getInstance()
之前,该内部类从未被触及。只要该内部类未被触及,它就不会被初始化。即使 new AwsCredentialsProvider()
需要一个小时,直到有人打电话给 .getInstance()
才花掉这个小时。