在地图中强制执行泛型类型(与键/值泛型相关)

时间:2012-01-31 23:45:27

标签: java generics

让我们说我想要某种类似

的缓存
Map<Class<T extends SomeBaseClass>, List<T>> cache = new ...

当我尝试这样做时会抛出编译错误。我不想让他们成为我工作的班级的仿制药,因为他们不属于那里。我也会有很多种不同的T.但是我也不想使用<? extends SomeBaseClass>,因为你没有编译时保证进入的列表与映射到它的类相同类型......

我有什么选择?这些条款在这里过度使用,在谷歌我似乎无法搜索它们: - (

4 个答案:

答案 0 :(得分:3)

没有选择。这是不可避免的,虽然你可以将它包装在你自己的隐藏类型转换的API中......但是在编译时没有办法在Java中保证这种东西。

也就是说,您可以创建一个在外部使用的类型安全的API,并在内部禁止警告。 (@ysdx建议查看Guava的ClassToInstanceMap,这确实是一个很好的例子。)但是你不会得到内部类型安全的东西:将会被施放里面。

答案 1 :(得分:3)

  

我也会有很多种不同的T。

如果我理解正确,你想要的是使用泛型以某种方式保证地图中的每个条目都将Class对象与相关类的某个对象相关联。

泛型无法做到这一点。让我们引用你的代码片段:

Map<Class<T extends SomeBaseClass>, List<T>> cache = new ...

看起来您希望Map中的每个条目都将Class对象与该类的实例相关联。好吧,泛型无法做任何事情来帮助你,因为T中的类型参数Map<Class<T>,T>将具有一个且仅当一个类型替换它时类型专用于特定T }。这意味着该类的专用Map<Class<Foo>,Foo>版本将具有带此签名的方法:

public Set<Map.Entry<Class<Foo>,Foo>> entries();

您从Map.Entry<Class<Foo>,Foo>>的{​​{1}}方法中获得的Set引用将包含以下方法:

iterator

在这种情况下,public Class<Foo> getKey(); public Foo getValue(); 只有一个值,它是Class<Foo>类的类对象。但是如果我们按照你的例子使用Foo并没有真正增加太多; Class<T extends SomeBaseClass>会为您提供一些getKey()对象,其Class方法会生成可以投放到newInstance的内容,但无法保证Foo会让您获得相同运行时类的值,甚至可以转换为与getValue()返回的类相同的类的类。

编辑:你可能想要这样的东西(未经测试,甚至没有尝试过编译):

getKey()

在您使用public class InstanceTable { private final Map<Class,Object> table = new ConcurrentHashMap<Class,Object>(); public <T> void put(Class<T> klass, T value) throws ClassCastException { table.put(klass.cast(value)); } public <T> T get(Class<T> klass) { return klass.cast(table.get(klass)) } } 语法静态命名源代码中使用的类的情况下,这提供了编译时类型安全

Foo.class

但要明白,除此之外,它没有使用类型系统在编译时强制执行你想要的不变量 - 它仍在运行时检查它(对Class.cast()的调用)。

答案 2 :(得分:0)

所以你想要一张

的地图
String.class --> list of strings
Int.class --> List of Integers

好的,没有概率。但是:在地图的特定实例中:

Map<K, V> x = …; 

具体的特定班级是什么?你想让它同时成为不同的一部分,这不会发生。

你将不得不做一些演员。

答案 3 :(得分:0)

我已在TypedMaphttp://blog.pdark.de/2010/05/28/type-safe-object-map/

中实现了此功能

以下是一些演示代码:

TypedMap map = new TypedMap();

String expected = "Hallo";
map.set( KEY1, expected );
String value = map.get( KEY1 ); // Look Ma, no cast!
assertEquals( expected, value );

List<String> list = new ArrayList<String> ();
map.set( KEY2, list );
List<String> valueList = map.get( KEY2 ); // Even with generics
assertEquals( list, valueList );

魔法在关键:

final static TypedMapKey<String> KEY1 = new TypedMapKey<String>( "key1" );
final static TypedMapKey<List<String>> KEY2 = new TypedMapKey<List<String>>( "key2" );