Общий InternPool <T>в Java? - PullRequest
       26

Общий InternPool <T>в Java?

9 голосов
/ 24 июля 2010

Как бы я написал общий InternPool<T> на Java?Нужен ли ему интерфейс Internable?

String в Java имеет возможности интернирования;Я хочу стажироваться в таких классах, как BigDecimal и Account.

Ответы [ 6 ]

5 голосов
/ 24 июля 2010

Для примера взгляните на <a href="https://google.github.io/guava/releases/21.0/api/docs/src-html/com/google/common/collect/Interner.html" rel="nofollow noreferrer">Interner</a> из Гуава . Он не требует Internable интерфейса, он просто использует equals и hashCode.

5 голосов
/ 24 июля 2010

Примерно так:

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

Это зависит от класса элемента пула, реализующего equals и hashCode для обеспечения «равенства по значению» и соблюдения контрактов API для этих методов. Но BigDecimal определенно делает.


ОБНОВЛЕНИЕ - объяснение того, почему нам нужен WeakHashMap<T, WeakReference<T>>, а не WeakHashMap<T, T>, см. javadocs . Краткая версия состоит в том, что ключевые слабые ссылки в последнем не будут разорваны GC, потому что соответствующие ссылки на записи делают значения полностью достижимыми.

3 голосов
/ 26 февраля 2014

Я бы разделил решение на два класса, чтобы иметь более чистый код, а также избавиться от цикла:

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

и интернирующий класс, использующий слабый пул, очень прост:

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;
    }
}
2 голосов
/ 24 июля 2010

Это больше похоже на то, что вы ищете образец в полулегком .

Flyweight - шаблон проектирования программного обеспечения.Flyweight - это объект, который минимизирует использование памяти за счет совместного использования как можно большего количества данных с другими подобными объектами

Нажмите на ссылку, она содержит пример Java.

1 голос
/ 27 октября 2014

Просто быстрое предупреждение:

Это не было явно упомянуто выше, но должно быть очевидно, что интернируемые объекты должны быть неизменяемого типа.

На втором примечании: вам не нужно использовать другую слабую ссылку на объект в качестве значения на карте, ссылка на статический будет достаточной, если вы просто полагаетесь на набор ключей карты для данных,Например, объявите:

WeakHashMap<T,Boolean>

И вставьте пары в виде:

pool.put (object, Boolean.TRUE);

Это незначительное сохранение экземпляра WeakReference (если вы не можете повторно использовать тот, который используется для ключа).

... или создайте класс WeakSet, как @PeterVerhas сделал со своим WeakPool.

0 голосов
/ 10 сентября 2015

не должен

"WeakReference ref = pool.get (object);"

вместо

WeakReference ref = pool.intern (объект);

??

...