Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Generic InternPool<T> in Java?

How would I write a generic InternPool<T> in Java? Does it need a Internable interface?

String in Java has interning capabilities; I want to intern classes like BigDecimal and Account.

like image 907
user400860 Avatar asked Jul 24 '10 04:07

user400860


4 Answers

Something like this:

public class InternPool<T> {

    private WeakHashMap<T, WeakReference<T>> pool = 
        new WeakHashMap<T, WeakReference<T>>();

    public synchronized T intern(T object) {
        T res = null;
        // (The loop is needed to deal with race
        // conditions where the GC runs while we are
        // accessing the 'pool' map or the 'ref' object.)
        do {
            WeakReference<T> ref = pool.get(object);
            if (ref == null) {
                ref = new WeakReference<T>(object);
                pool.put(object, ref);
                res = object;
            } else {
                res = ref.get();
            }
        } while (res == null);
        return res;
    }
}

This depends on the pool element class implementing the equals and hashCode to provide "equality by value" and to obey to the API contracts for those methods. But BigDecimal certainly does.


UPDATE - for an explanation of why we need a WeakHashMap<T, WeakReference<T>> rather than a WeakHashMap<T, T>, see the javadocs. The short version is that the key weak-links in the latter won't be broken by the GC because the corresponding entry references are making the values strongly reachable.

like image 173
Stephen C Avatar answered Sep 28 '22 01:09

Stephen C


For an example take a look at Interner from Guava. It does not require an Internable interface, it just relies on equals and hashCode.

like image 35
finnw Avatar answered Sep 28 '22 03:09

finnw


I would separate the solution into two classes to have cleaner code and also this way getting rid of loop:

public class WeakPool<T> {
    private final WeakHashMap<T, WeakReference<T>> pool = new WeakHashMap<T, WeakReference<T>>();
    public T get(T object) {
        final T res;
        WeakReference<T> ref = pool.get(object);
        if (ref != null) {
            res = ref.get();
        } else {
            res = null;
        }
        return res;
    }
    public void put(T object) {
        pool.put(object, new WeakReference<T>(object));
    }
}

and the interning class using the weak pool is very simple:

public class InternPool<T> {

    private final WeakPool<T> pool = new WeakPool<T>();

    public synchronized T intern(T object) {
        T res = pool.get(object);
        if (res == null) {
            pool.put(object);
            res = object;
        }
        return res;
    }
}
like image 39
Peter Verhas Avatar answered Sep 28 '22 02:09

Peter Verhas


This more sounds like that you're looking for flyweight pattern.

Flyweight is a software design pattern. A flyweight is an object that minimizes memory use by sharing as much data as possible with other similar objects

Click the link, it contains a Java example.

like image 21
BalusC Avatar answered Sep 28 '22 01:09

BalusC