在 Java 中是否可以创建类型安全的类到类实例的映射?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/6795025/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
In Java is it possible to create a type-safe Map of classes to instances of their class?
提问by Sled
I would like to create a map that uses a class as a key to return an instance of that class. Something like:
我想创建一个地图,该地图使用一个类作为返回该类实例的键。就像是:
<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 );
Is this possible? I have a feeling that no it is not because I cannot indicate that T
is meant to be a generic type rather than a class named "T". It is feels somehow like "higher-order generics".
这可能吗?我有一种感觉,不,这不是因为我不能表明它T
是一个泛型类型,而不是一个名为“T”的类。感觉有点像“高阶泛型”。
EDIT:I know I could try to extend Map and implement my own wrapper etc, but I am specifically asking about doing this just using using Java's generic support. I am more interested in the idea rather than this particular case.
编辑:我知道我可以尝试扩展 Map 并实现我自己的包装器等,但我特别要求仅使用 Java 的通用支持来执行此操作。我对这个想法更感兴趣,而不是这个特殊案例。
EDIT 2:As pointed out below, this is a duplicate (or more specifically a subcase) of the question: Java map with values limited by key's type parameter. Had I been able to find wording as eloquent as that, I would have likely found that answer and not posted this.
编辑 2:正如下面所指出的,这是问题的重复(或更具体地说是一个子案例):Java map with values limited by key's type parameter。如果我能够找到像那样雄辩的措辞,我可能会找到那个答案而不是发布这个。
采纳答案by Jay
As I understand you, you're saying that after you create this map, you want to populate it with something like ...
据我了解,您是说在创建此地图后,您想用类似...的内容填充它。
f.put(String.class, "Hello");
f.put(Integer.class, new Integer(42));
f.put(x.getClass(), x);
etc. Right?
等等,对吗?
In that case, I think the answer is no, you cannot do that with generics. Generics say that for a given instance of the class -- the map in this case -- you are specifying the types that are applicable. So if you say new HashMap<String,Integer>;
, you are saying that all operations against this map will use a key that is a string and a value that is an integer. But that's not what you want to do in this case. You want to be able to put any sort of object into the class, and then constrain the acceptable types for the key based on the type of the object. That's not how generics work. They're not a relationship between each other, they're a constant for any given instance.
在那种情况下,我认为答案是否定的,你不能用泛型来做到这一点。泛型说对于给定的类实例——在这种情况下是映射——你指定了适用的类型。所以如果你说new HashMap<String,Integer>;
,你是说针对这个映射的所有操作都将使用一个字符串键和一个整数值。但在这种情况下,这不是您想要做的。您希望能够将任何类型的对象放入类中,然后根据对象的类型限制键的可接受类型。这不是泛型的工作方式。它们不是彼此之间的关系,对于任何给定的实例,它们都是常量。
You could, of course, create such a map as new HashMap<Class,Object>;
. This wouldn't force the class to be the class of the corresponding object, but it would allow you to enter such values.
当然,您可以创建这样的地图new HashMap<Class,Object>;
。这不会强制该类成为相应对象的类,但它允许您输入此类值。
Besides that, I think you'd need a wrapper. Should I point out that the wrapper's put would only need one parameter, as it could presumably determine the class of the parameter by doing getClass()
on it, there'd be no need to tell it?
除此之外,我认为你需要一个包装器。我是否应该指出包装器的 put 只需要一个参数,因为它大概可以通过对其进行操作来确定参数的类别,而getClass()
无需告诉它?
回答by fyr
You mean something like this ?
你的意思是这样的?
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);
}
}
see as reference: Java map with values limited by key's type parameter
请参阅参考:Java 映射,其值受键的类型参数限制
回答by Kirk Woll
In your example, T
would have to be different for each key/value, whereas with generics, T
must be the same for each key/value. So no, this is not possible using generics. (but of course the implementation is certainly possbile with casting and/or not using generics)
在您的示例中,T
每个键/值必须不同,而对于泛型,T
每个键/值必须相同。所以不,这是不可能使用泛型的。(但当然,实现肯定可以通过转换和/或不使用泛型)
回答by dlev
The point of Map<T, U>
is to map T's to U's. T and U can be any class (assuming no wildcards), but once they are determined, they can't change. In your case, you'd like a mapping that returned a different class depending on what key you used, which is obviously different.
重点Map<T, U>
是将 T 映射到 U。T 和 U 可以是任何类(假设没有通配符),但是一旦确定,它们就无法更改。在您的情况下,您希望映射根据您使用的键返回不同的类,这显然是不同的。
The usual way to go about this is just make U Object
, since you can go ahead and cast it to whatever you need. But of course this breaks the type-safety that generics are supposed to provide.
通常的方法是 make U Object
,因为您可以继续将其转换为您需要的任何内容。但这当然打破了泛型应该提供的类型安全性。
In short, I don't think this would be possible without writing a wrapper of some kind.
简而言之,如果不编写某种包装器,我认为这是不可能的。
回答by ColinD
T
must be set to some specific type when an instance is created, so you wouldn't be able to add different types to the map using the put
method. Generic methods, on the other hand, have their type arguments set when they are called, allowing you to do what you want.
T
创建实例时必须将其设置为某种特定类型,因此您将无法使用该put
方法向地图添加不同的类型。另一方面,泛型方法在调用时设置了它们的类型参数,允许你做你想做的事。
Guavahas a ClassToInstanceMaptype that uses generic methods to handle safely putting instances in the map and getting them out.
Guava有一个ClassToInstanceMap类型,它使用通用方法来安全地将实例放入映射中并取出它们。