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

时间:2011-07-22 19:25:26

标签: java generics

我想创建一个使用类作为键来返回该类实例的映射。类似的东西:

<T> Map< Class<T>, T > instanceMap = new HashMap< Class<T>, 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”的类。感觉就像是“高阶泛型”。

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

编辑2:如下所述,这是问题的重复(或更具体地说是子案例):Java map with values limited by key's type parameter。如果我能够找到那样雄辩的措辞,我可能会找到答案而不是发布这个。

6 个答案:

答案 0 :(得分:13)

你的意思是这样的吗?

public class Favorites {
  private Map<Class<?>, Object> favorites =
    new HashMap<Class<?>, Object>();

  public <T> void setFavorite(Class<T> klass, T thing) {
    favorites.put(klass, thing);
  }

  public <T> T getFavorite(Class<T> 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 map with values limited by key's type parameter

答案 1 :(得分:3)

据我了解,您说在创建此地图后,您希望使用类似的内容填充它...

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

等。正确?

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

当然,您可以创建new HashMap<Class,Object>;这样的地图。这不会强制类成为相应对象的类,但它允许您输入这样的值。

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

答案 2 :(得分:1)

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

答案 3 :(得分:0)

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

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

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

答案 4 :(得分:0)

创建实例时,必须将

T设置为某种特定类型,因此您无法使用put方法向地图添加不同类型。另一方面,通用方法在调用它们时设置了它们的类型参数,允许你做你想做的事。

GuavaClassToInstanceMap类型,它使用通用方法来处理安全地将实例放入地图并将其删除。

答案 5 :(得分:0)

JsonObject可能是一个选项。 您可以将任何您喜欢的内容作为jsonobject的值。你需要的是包org.json.JSONObject。但是,您可能无法将foreach与JSONObject一起使用,但有一些替代方法How to iterate over a JSONObject?