Как я могу хранить универсальные типы в кэше, чтобы избежать непроверенных приведений при поиске? - PullRequest
4 голосов
/ 21 ноября 2010

Необходимо стереть некоторые детали этого, но в основном я пытаюсь кэшировать результат дорогостоящей операции, которая возвращает коллекцию объектов, но типы этих отдельных объектов не известны во время компиляции (толькобазовый класс).

public class SomeClass
{
    private static final Map<Integer,Collection<? extends SomeBaseClass>> theCache = new HashMap<Integer,Collection<? extends SomeBaseClass>>();

    public <T extends SomeBaseClass> Collection<T> theMethod(Class<T> theClass, int index)
    {
        if (theCache.containsKey(index))
        {
            return (Collection<T>) theCache.get(index);
        }
        else
        {
            Collection<T> result = someExpensiveOperation(theClass, index);
            theCache.put(index, result);
            return result;
        }
    }

    // ...

}

Здесь извлечение из кэша является непроверенным приведением, поскольку код просто полагается на то, что аргумент класса, переданный в метод вызывающей стороной, совместим (должен быть идентичен) стот, который был передан предыдущим вызовом, который сначала создал объект в кеше.

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

Ответы [ 2 ]

3 голосов
/ 21 ноября 2010

Нет прямой поддержки этого поведения.

Если в кеше содержатся отдельные элементы, вы можете использовать Class.cast(), в случае несоответствия выдается ClassCastException:

private Map<Integer, ?> cache = ...;

public <T> T get(Integer id, Class<T> c) {
    return c.cast(cache.get(id));
}

В случае кэшированных коллекций это будет более сложным. Если вы действительно хотите избежать неконтролируемого приведения, вы можете создать новую коллекцию и заполнить ее с помощью Class.cast():

Collection<T> result = ...;
for (Object o: theCache.get(index)) 
    result.add(theClass.cast(o));
return result;

Другие подходы включают, например, создание «проверенного» представления коллекции с использованием Collections2.transform():

в Guava
public class Cast<T> implements Function<Object, T> {
    private Class<T> type;
    public Cast(Class<T> type) {
        this.type = type;
    }

    public T apply(Object in) {
        return type.cast(in);
    }
}

.

return Collections2.transform(theCache.get(index), new Cast<T>(theClass));
0 голосов
/ 21 ноября 2010

Есть много возможных способов справиться с этим.Вот что я хотел бы сделать - создать класс Collection, который хранит его тип элемента:

class TypedList<T> extends ArrayList<T> {

    private Class<T> type;

    TypedList(Class<T> type) {
        super();
        this.type = type;
    }

    Class<T> getType() {
        return type;
    }
}

и убедиться, что someExорогоOperation () использует этот класс для возврата своих результатов.Таким образом, вы сможете запросить тип при получении элемента кэша.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...