在Java中,是否可以为类的实例创建类型安全的类映射?

我想创建一个使用类作为键来返回该类实例的映射。 就像是:

 Map< Class, T > instanceMap = new HashMap< Class, T > (); instanceMap.put( Boolean.class, Boolean.TRUE ); instanceMap.put( String.class, "asdf" ); instanceMap.put( Integer.class, 11 ); Boolean b = instanceMap.get( Boolean.class ); Integer i = instanceMap.get( Integer.class ); String s = instanceMap.get( String.class ); 

这可能吗? 我有一种感觉,不是不是因为我不能指出T是一个通用类型而不是一个名为“T”的类。 感觉就像是“高阶generics”。

编辑:我知道我可以尝试扩展Map并实现我自己的包装器等,但我特别要求使用Java的通用支持来做这个。 我对这个想法更感兴趣而不是这个特殊情况。

编辑2:如下所述,这是问题的重复(或更具体地说是一个子案例): Java地图,其值受键的类型参数限制 。 如果我能够找到那样雄辩的措辞,我很可能会找到答案,而不是发布这个。

据我了解你,你说在创建这个地图后,你想要用类似的东西来填充它。

 f.put(String.class, "Hello"); f.put(Integer.class, new Integer(42)); f.put(x.getClass(), x); 

对吧?

在这种情况下,我认为答案是否定的,你不能用generics来做到这一点。 generics说,对于类的给定实例 – 本例中的映射 – 您指定了适用的类型。 所以如果你说new HashMap; ,你是说对这个映射的所有操作都将使用一个字符串键和一个整数值。 但在这种情况下,这不是你想要做的。 您希望能够将任何类型的对象放入类中,然后根据对象的类型约束键的可接受类型。 这不是generics如何工作。 它们不是彼此之间的关系,它们对于任何给定的实例都是常数。

当然,您可以创建一个new HashMap; 。 这不会强制类成为相应对象的类,但它允许您输入这些值。

除此之外,我认为你需要一个包装器。 我是否应该指出包装器的put只需要一个参数,因为它可能通过对它执行getClass()来确定参数的类,没有必要告诉它?

你的意思是这样的?

 public class Favorites { private Map, Object> favorites = new HashMap, Object>(); public  void setFavorite(Class klass, T thing) { favorites.put(klass, thing); } public  T getFavorite(Class klass) { return klass.cast(favorites.get(klass)); } public static void main(String[] args) { Favorites f = new Favorites(); f.setFavorite(String.class, "Java"); f.setFavorite(Integer.class, 0xcafebabe); String s = f.getFavorite(String.class); int i = f.getFavorite(Integer.class); } } 

作为参考: Java映射的值受键的类型参数限制

在您的示例中,每个键/值的T必须不同,而对于generics,每个键/值的T必须相同。 所以不,使用generics这是不可能的。 (但当然,实施当然可以使用强制转换和/或不使用generics)

Map的要点是将T’映射到U’。 T和U可以是任何类(假设没有通配符),但一旦确定,它们就不能改变。 在您的情况下,您希望映射根据您使用的密钥返回不同的类,这显然是不同的。

通常的方法就是制作U Object ,因为你可以继续将它投射到你需要的任何东西上。 但是,这当然打破了仿制药应该提供的类型安全性。

简而言之,如果不编写某种包装,我认为这是不可能的。

创建实例时,必须将T设置为某种特定类型,因此您无法使用put方法向地图添加不同类型。 另一方面,通用方法在调用它们时设置了它们的类型参数,允许您执行所需的操作。

Guava有一个ClassToInstanceMap类型,它使用generics方法来处理安全地将实例放入地图并将其取出。

JsonObject可能是一个选项。 你可以把你喜欢的任何东西作为jsonobject的值。 你需要的是包org.json.JSONObject。 但是,您可能无法将foreach与JSONObject一起使用,但是有一些替代方法如何迭代JSONObject?