[英]Java Map with variable generics as values
So here's a slightly tricky question (for me). 所以这是一个对我来说有点棘手的问题。
I have a generic object. 我有一个通用对象。 Call it MyObject. 称之为MyObject。 This object has a method which returns something of the type T: 这个对象有一个返回类型T的方法:
public class MyObject<T>
{
private T _t;
public MyObject(T t)
{
_t = t;
}
//...
public T get()
{
return _t;
}
}
(Obviously my "MyObject" does a bit more but that's the gist). (显然,我的“ MyObject”的作用要大一些,但这是要点)。
Now, I want to have a map of this type: 现在,我想要一张这种类型的地图:
Map<String, MyObject<?>> m = new HashMap<>();
I want to be able to fetch maps using some predefined string name, and these maps can be of any MyObject. 我希望能够使用一些预定义的字符串名称来获取映射,并且这些映射可以是任何MyObject的。 For example, I could call: 例如,我可以打电话给:
m.put("map_1", new MyObject<String>("String"));
m.put("map_2", new MyObject<Integer>(new Integer(3));
m.put("map_3", new MyObject<Long>(new Long(5));
etc. 等等
But - and here's the tricky part - I want the map to "remember" the parameterized type of MyObject when I fetch some value from the map. 但是-这是棘手的部分-当我从地图中获取某些值时,我希望地图“记住” MyObject的参数化类型。 Using 使用
m.get("map_1");
would return a 会返回一个
MyObject<Object>
type, since the map was defined as containing 类型,因为地图被定义为包含
MyObject<?>
values. 价值观。 Thus: 从而:
m.get("map_1").get() // <-- This is an Object, not a String!
What modification (if any) is possible, in order to be able to get the correct - full - information regarding the MyObject fetched object, such that invoking the last line (m.get("map_1")) would return a 为了能够获取有关MyObject获取的对象的正确的完整信息,可以进行任何修改(如果有的话),以便调用最后一行(m.get(“ map_1”))将返回a
MyObject<String>
Thanks :) 谢谢 :)
Amir. 阿米尔。
Typesafe Heterogeneous Containers from Joshua Bloch's Effective Java might work here. Joshua Bloch的Effective Java中的 Typesafe异构容器可能在这里起作用。 Basically you add a Class
object to represent the type. 基本上,您添加了一个Class
对象来表示类型。
public class MyObject<T>
{
private T _t;
private Class<T> type;
public MyObject( Class<T> type, T t)
{
_t = t;
this.type = type;
}
//...
public T get()
{
return _t;
}
public Class<T> getType() { return type; }
}
Then you could do something like this: 然后,您可以执行以下操作:
public <T> T get( Map<String, MyObject<?>> map, String key, Class<T> type ) {
return type.cast( m.get( key ).get() );
}
Which is safe and will compile, but will throw a runtime error if you get the type wrong. 这是安全的,可以编译,但是如果您输入的类型错误,则会抛出运行时错误。
(Note I didn't actually compile that, so I might have syntax errors floating around. But most folks don't know how to use Class
to cast objects.) (请注意,我实际上并没有进行编译,因此可能会出现语法错误。但是大多数人都不知道如何使用Class
来转换对象。)
You can get the class. 你可以上课。
Class c = m.get("map_1").get().getClass();
if (String.class.equals(c)) {
System.out.println("its a String");
}
Here is a full test. 这是一个完整的测试。
public class GenericsTest {
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
Map<String, MyObject<?>> map = new HashMap<>();
MyObject<String> obj = new MyObject<>("hello");
map.put("greeting", obj);
Class c = map.get("greeting").get().getClass();
if (String.class.equals(c)) {
System.out.println("its a String");
}
}
static class MyObject<T> {
T t;
public MyObject(T t) {
this.t = t;
}
T get() {
return t;
}
}
}
The type system only knows about types, not objects, and therefore can not distinguish "key1"
from "key2"
, because both are of type String
. 类型系统只知道类型,而不知道对象,因此不能区分"key1"
和"key2"
,因为两者都是String
类型。
If keys have different types, the easiest way is to encapsulate a weakly typed map, and use reflective casts to prove to the compiler the types are correct: 如果键具有不同的类型,则最简单的方法是封装弱类型映射,并使用反射型强制转换向编译器证明类型正确:
class Favorites {
private Map<Class<?>,?> map = new HashMap<>();
<V> V get(Class<V> clazz) {
return clazz.cast(map.get(clazz));
}
<V> void put(Class<V> clazz, V value) {
map.put(clazz, value);
}
}
Favorites favs = new Favorites();
favs.put(String.class, "hello");
favs.put(Integer.class, 42);
favs.get(String.class).charAt(1);
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.