开发者

How to prevent multiple object instantiations of a certain class

开发者 https://www.devze.com 2023-02-17 22:13 出处:网络
MyInterface intf = (MyInterface) Class.forName(className).newInstance(); I have a certain piece of code which will create new interfaces on demand using the above call and invoke a certain method. A
MyInterface intf = (MyInterface) Class.forName(className).newInstance();

I have a certain piece of code which will create new interfaces on demand using the above call and invoke a certain method. All of the implementation classes usually contain lots of final static variables and static initialization code which I would like to fire only once in its lifetime.

But since I am using the newInstance() call, I am under the impression that the old object gets GCed and the class is initialized agai开发者_如何学Pythonn and hence all the static variables.

In order to avoid this, I would like to put this in a cache, so that these classes are not re-constructed again and hence would be initialized once during its lifetime. (Note: My interfaces are thread-safe).

Should I just put this in a Hashtable and just look it up or is there a better way to handle the cache?


All of the implementation classes usually contain lots of final static variables and static initialization code which I would like to fire only once in its lifetime.

But since I am using the newInstance() call, I am under the impression that the old object gets GCed and the class is initialized again and hence all the static variables.

No, this is not true. Static fields and static blocks only run once -- when the class is loaded. So creating instances repeatedly will not rerun them. Also, they will not be garbage collected. So you don't have to worry about static fields being GCed and recreated repeatedly :-).

Additional note:

The above only applies if you only use the default classloader. If you use multiple classloaders and unload a classloader, then all the classes it loaded, along with their static fields will become eligible for GC. Also, static fields exist per classloader, not only per class, so if you load the same class using different classloaders, static initialization will indeed run multiple times. But this may not be a cocern for you...

Also see the discussion here:

Are static fields open for garbage collection?


If I understand correctly you need to create new instances of your classes, and you want to be sure some initialization code is executed only once, and not every time that you call newInstance(). I think that if you put the initialization code in a static section, then you're fine: AFAIK the code in a static initializer block is executed once by the virtual machine when the class is loaded. See also this question.


How about something like this:

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;
}

This will guarantee that only one instance of each class is used (as long as you only use this method)

Example Usage:

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

Using Guava, this code could be improved 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);
}


How about this one.

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;
}


Use the singleton pattern: http://en.wikipedia.org/wiki/Singleton_pattern


This is called Singleton.
Using this pattern there'll be only one instance of your class.
There are some exceptions, however for most purposes you'll only have one instance.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号