在 Java 中,是不是可以创建一个类型安全的类映射到其类的实例?
Posted
技术标签:
【中文标题】在 Java 中,是不是可以创建一个类型安全的类映射到其类的实例?【英文标题】:In Java is it possible to create a type-safe Map of classes to instances of their class?在 Java 中,是否可以创建一个类型安全的类映射到其类的实例? 【发布时间】:2011-10-11 07:43:55 【问题描述】:我想创建一个使用类作为键来返回该类的实例的映射。比如:
<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。如果我能找到如此雄辩的措辞,我很可能会找到那个答案,而不是发布这个。
【问题讨论】:
每个类(键)只能存储一个值? @home 是的,这将被用作访问 DAO 的一种方式,其中每个 dao 类型只需要一个 dao。 JsonObject 可能是一个选项。您可以将任何您喜欢的值作为 jsonobject 的值。您需要的是包 org.json.JSONObject。但是,您可能无法将 foreach 与 JSONObject 一起使用,但有一些替代方法 ***.com/questions/9151619/… 如果你可以坚持任何你想要的,那么它就不是类型安全的。我特别希望将键的类型与值的类型联系起来。您的建议似乎与Map<String,Object>
一样安全。
【参考方案1】:
你的意思是这样的?
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
【讨论】:
我知道这可以用包装器来完成,我问的是使用纯泛型,但我假设你在我编辑之前回答了。 为了澄清我之前的评论,我对泛型类型系统的局限性更感兴趣,并制作了说明性示例来帮助构建问题。这就是为什么我没有接受你的很多赞成和其他合理的答案(即它回答了我要去的特定而不是一般)【参考方案2】:据我了解,您是说在创建此地图后,您想用类似...的内容填充它
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()
来确定参数的类,不需要告诉它?
【讨论】:
【参考方案3】:在您的示例中,T
对于每个键/值必须不同,而对于泛型,T
对于每个键/值必须相同。所以不,这是不可能使用泛型的。 (但当然可以通过强制转换和/或不使用泛型来实现)
【讨论】:
我也很怀疑,我只是想确保我没有遗漏什么。但是with generics, T must be the same for each key/value
听起来像是继承自 C++ 的限制,而不是 Java 泛型需要具备的限制;毕竟,在我的示例中,它仍然是静态可验证的。【参考方案4】:
Map<T, U>
的重点是将 T 映射到 U。 T 和 U 可以是任何类(假设没有通配符),但一旦确定,就不能更改。在您的情况下,您想要一个根据您使用的键返回不同类的映射,这显然是不同的。
解决这个问题的通常方法是制作 U Object
,因为您可以继续将其转换为您需要的任何内容。但这当然破坏了泛型应该提供的类型安全性。
简而言之,如果不编写某种包装器,我认为这是不可能的。
【讨论】:
【参考方案5】:T
在创建实例时必须设置为某种特定类型,因此您将无法使用put
方法将不同类型添加到地图中。另一方面,泛型方法在调用它们时会设置其类型参数,从而允许你做你想做的事情。
Guava 有一个 ClassToInstanceMap 类型,它使用泛型方法来处理将实例安全地放入地图并取出它们。
【讨论】:
以上是关于在 Java 中,是不是可以创建一个类型安全的类映射到其类的实例?的主要内容,如果未能解决你的问题,请参考以下文章