如何防止某个类的多个对象实例化

时间:2011-03-17 11:24:12

标签: java

MyInterface intf = (MyInterface) Class.forName(className).newInstance();

我有一段代码,它将使用上述调用按需创建新接口并调用某种方法。所有的实现类通常都包含许多final static变量和静态初始化代码,我想在其生命周期中只触发一次。

但是由于我正在使用newInstance()调用,所以我觉得旧对象得到GCed并且类再次被初始化,因此所有静态变量都被初始化。

为了避免这种情况,我想把它放在一个缓存中,这样这些类就不会再次重构,因此在它的生命周期内会被初始化一次。 (注意:我的接口是线程安全的。)

我应该把它放在Hashtable中,然后查一下,还是有更好的方法来处理缓存?

6 个答案:

答案 0 :(得分:6)

  

所有实现类   通常包含大量的最终静态   变量和静态初始化   我想要解雇的代码   一生一次。

     

但是因为我正在使用newInstance()   打电话,我的印象是   旧对象得到了GCed和类   再次初始化,因此所有的   静态变量。

不,这不是真的。静态字段和静态块只运行一次 - 加载类时。因此,重复创建实例不会重新运行它们。此外,他们不会被垃圾收集。因此,您不必担心静态字段被GCed并重复重新创建: - )。

附加说明:

以上仅适用于仅使用默认类加载器的情况。如果您使用多个类加载器并卸载类加载器,那么它加载的所有类以及它们的静态字段符合GC的条件。此外,静态字段存在每个类加载器,而不仅仅是每个类,因此如果使用不同的类加载器加载相同的类,静态初始化将确实运行多次。但这可能不适合你...

另见这里的讨论:

Are static fields open for garbage collection?

答案 1 :(得分:3)

如果我理解正确,你需要创建类的新实例,并且你想确保一些初始化代码只执行一次,而不是每次调用newInstance()。我认为如果你把初始化代码放在一个静态部分,那么你很好:AFAIK静态初始化程序块中的代码在加载类时由虚拟机执行一次。另请参阅此question

答案 2 :(得分:2)

这样的事情怎么样:

private static Map<String, Object> cache = 
    new ConcurrentHashMap<String, Object>();

@SuppressWarnings("unchecked")
public static <T> T getImplementation(final String implementationClass){
    T result;
    synchronized(cache){
        result = (T) cache.get(implementationClass);
        if(result == null){
            try{
                result =
                    (T) Class.forName(implementationClass).newInstance();
            } catch(final Exception e){
                // error handling here
            }
            cache.put(implementationClass, result);
        }
    }
    return result;
}

这将保证每个类只使用一个实例(只要你只使用这个方法)

使用示例:

FooService service = getImplementation("com.mycompany.FooServiceImpl");

使用Guava,可以改进此代码with a Computing Map

private static Map<String, Object> cache =
     new MapMaker().makeComputingMap(
         new Function<String, Object>(){

            @Override
            public Object apply(final String input){
                try{
                    return Class.forName(input).newInstance();
                } catch(final Exception e){
                    // error handling here
                }
            }
         });

@SuppressWarnings("unchecked")
public static <T> T getImplementation(final String implementationClass){
    return (T) cache.get(implementationClass);
}

答案 3 :(得分:2)

这个怎么样。

static final Map<String, Object> instances = new HashMap<String, Object>();

public static Object getInstance(String name) {

    if (name == null) {
        return null;
    }
    Object obj = null;

    synchronized (ClassName.class) {
        try {
            obj = instances.get(name);
            if (obj == null) {
                obj = Class.forName(name).newInstance();
                instances.put(name, obj);
            }
        } catch (ClassNotFoundException e) {
        } catch (InstantiationException e) {
        } catch (IllegalAccessException e) {
        }
    }
    return obj;
}

答案 4 :(得分:1)

答案 5 :(得分:0)

这称为Singleton
使用这种模式,你的班级只有一个实例。
有一些例外,但是对于大多数目的,你只有一个实例。