代码之家  ›  专栏  ›  技术社区  ›  Adam Burley

如何将泛型类型存储在缓存中,以避免在检索时进行未检查的强制转换?

  •  4
  • Adam Burley  · 技术社区  · 14 年前

    必须删除其中的一些细节,但基本上我正在尝试缓存一个昂贵的操作的结果,该操作返回一个对象集合,但是在编译时不知道这些单独对象的类型(仅基类)。

    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 回复  |  直到 14 年前
        1
  •  3
  •   axtavt    14 年前

    这种行为没有直接的支持。

    如果缓存包含单个元素,则可以使用 Class.cast() ,它抛出一个 ClassCastException 如果不匹配:

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

    在缓存集合的情况下,这将更加复杂。如果您确实希望避免未选中的强制转换,则可以创建一个新集合并通过 类。cast() :

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

    其他方法包括,例如,使用番石榴的 Collections2.transform() :

    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));
    
        2
  •  0
  •   Mike Baranczak    14 年前

    有很多可能的方法来处理这个问题。下面是我要做的-创建一个存储其元素类型的集合类:

    class TypedList<T> extends ArrayList<T> {
    
        private Class<T> type;
    
        TypedList(Class<T> type) {
            super();
            this.type = type;
        }
    
        Class<T> getType() {
            return type;
        }
    }
    

    并确保someExpensiveOperation()使用该类返回其结果。这样,在检索缓存项时就可以查询类型。