繁体   English   中英

使用Java HashMap多个Type

[英]Use Java HashMap multiple Type

我正在使用Hashmap作为我的内存缓存。 基本上,这就是我所拥有的:

private static final Map<String, Object> lookup = new HashMap<String, Object>();

    public static Object get(CacheHelper key) {
        return lookup.get(key.getId());
    }

    public static void store(CacheHelper key, Object value) {
        lookup.put(key.getId(), value);
    }

没关系。 但对于我从地图中“获取”的每个物体,我必须施放,这非常难看。 我想把ArrayList和许多其他不同的东西放进去。

有人知道其他解决方案是类型安全的吗?

(当然,我可以为每种类型创建一个getter和setter,但这是唯一的解决方案吗?

那么,是否有更好的方法来创建内存缓存,或者有人知道如何将hashmap包装起来更安全吗?

解决此问题的一个方法是使用CacheHelper<T>使您的CacheHelper类型通用。 然后为地图创建一个包装器:

class MyCache {
  private final Map<CacheHelper<?>, Object> backingMap = new HashMap<>();
  public <T> void put(CacheHelper<T> key, T value) {
    backingMap.put(key, value);
  }
  @SuppressWarnings("unchecked")
  // as long as all entries are put in via put, the cast is safe
  public <T> T get(CacheHelper<T> key) {
    return (T) backingMap.get(key);
  }
}

Java编译器实际上在内部使用这种方法; 这里 您不必传递显式的Class对象,但您必须知道与每个键实际关联的类型,这与应该在行为良好的应用程序中应该相同。

你可以很好地存储元素的类型,将你期望的类型传递给get()方法并检查那里。 AFAIK没有内置的方法来存储不同类型的类型安全而没有一些常见的超类或接口。

基本上你这样做:

private static final Map<String, Object> lookup = new HashMap<>();
private static final Map<String, Class<?>> types= new HashMap<>();   

public static <T> T get(CacheHelper key, Class<T> expectedType ) {
  Class<?> type = types.get(key.getId());
  if( type == null || expectedType == null || expectedType.isAssignableFrom( type ) ) {
    throw new IllegalArgumentException("wrong type");
  }   
  return (T)lookup.get(key.getId());
}

//if null values should be allowed, you'd need to change the signature to use generics 
//and pass the expected type as well, e.g. <T> void store(CacheHelper key, T value, Class<T> type) 
public static void store(CacheHelper key, Object value ) {
    lookup.put(key.getId(), value);
    types.put( key.getId(), value.getClass() );
}

请注意,由于您基本上禁用了缓存中的泛型,因此仍然无法捕获任何编译时错误。 如果没有常见的超类/接口或缓存本身的泛型类型,那么就没有编译时间来捕获这些错误 - 至少不容易。

如果你只是不想自己进行强制转换,你可以将它们隐藏在get()并使用可能的类强制转换异常。 在这种情况下,您可以让编译器从调用中推断出T的类型(通过赋值,显式设置或参数类型)。

但是,传递期望的类很容易提供额外的信息,您可以使用它们来创建更好的错误消息等,这些消息是您从ClassCastException获得的。

您可以将Class对象作为参数传递,并使用Class.cast方法:

public static <T> T get(CacheHelper key, Class<T> clazz){
    return clazz.cast(lookup.get(key.getId());
}

如果java版本为7(或更高版本),您可以使用generics功能

public static <T> T get(CacheHelper key){
    return (T)(lookup.get(key.getId());
}

然后你可以按如下方式调用它:

Myclass.<String>get(key);

在上面的例子中,我认为Myclass是一个包含get()方法的类

get需要一个Class<T> ,因为类型擦除,一个演员(T)是一个无意义的无操作。

要么一直包括班级; 每班ID:

private final Map<Class<?>, Map<String, Object>> lookup = new HashMap<>();

public <T> T get(Class<T> klass, String id) {
    Map<String, Object> mapById = lookup.get(klass);
    if (mapById == null) {
        return null;
    }
    Object value = mapById.get(id);
    return klass.cast(value);
}

public <T> void store(Class<T> klass, String id, T value) {
    Map<String, Object> mapById = lookup.get(klass);
    if (mapById == null) {
        mapById = new HashMap<>();
        lookup.put(klass, mapById);
    }
    mapById.put(id, value);
}

store不使用value.getClass()来允许get by接口或基类:

store(Number.class, "x", 3.14);
store(Number.class, "x", 3);
store(Number.class, "x", new BigDecimal("3.14"));

或者只做

public static <T> T get(Class<T> klass, String id) {
    Object value = lookup.get(id);
    return klass.cast(value);
}

(我为读者简化了原始代码。)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM