我无法弄清楚使用泛型的正确方法。我有一个类Foo
,它有一个通用的(Foo<class>
)。然后我想要一张Map<String, Foo>
的地图。现在,我可以执行此操作,并将Foo<String>
添加为一个地图项,将Foo<Integer>
添加为另一个。但是,当我使用map的get方法时,我只返回Foo
并且无法再推断出类型,所以如果我这样做:
String s = map.get("StringFoo")
我遇到编译错误,必须这样做:
String s =(String)map.get(“StringFoo”)
做这样的事情有什么好的模式来避免演员,因为这首先是通用的。我或许可以做Map<String, Foo<?>>
这样的事情,但是这样做的方法是什么?
我的代码详情如下,可以将其放入目录中,javac *.java && java Main
将运行它。
我在Foo.java中有一个通用的java类,
public class Foo<T>
{
T value;
public T getValue()
{
return this.value;
}
public void setValue(T t)
{
this.value = t;
}
}
现在,我在Main.java中有以下测试类:
import java.util.Map;
import java.util.HashMap;
public class Main
{
public static void main(String[] a)
{
Foo<String> fooStr = new Foo<String>();
fooStr.setValue("TEST 123");
Foo<Integer> fooInt = new Foo<Integer>();
fooInt.setValue(314159);
Map<String, Foo> mapOfFoo = new HashMap<String, Foo>();
mapOfFoo.put("Strings", fooStr);
mapOfFoo.put("Integer", fooInt);
System.out.println("All set");
String s = mapOfFoo.get("Strings").getValue();
System.out.println("Got: " + s);
}
}
编译时,我收到以下错误:
Main.java:21: error: incompatible types
String s = mapOfFoo.get("Strings").getValue();
^
required: String
found: Object
1 error
当我在Main.java中执行此操作时,它可以工作:
import java.util.Map;
import java.util.HashMap;
public class Main
{
public static void main(String[] a)
{
Foo<String> fooStr = new Foo<String>();
fooStr.setValue("TEST 123");
Foo<Integer> fooInt = new Foo<Integer>();
fooInt.setValue(314159);
Map<String, Foo> mapOfFoo = new HashMap<String, Foo>();
mapOfFoo.put("Strings", fooStr);
mapOfFoo.put("Integer", fooInt);
System.out.println("All set");
String s = (String)mapOfFoo.get("Strings").getValue();
System.out.println("Got: " + s);
}
}
我不确定这样的事情的最佳做法是什么。有没有人有任何建议?
答案 0 :(得分:4)
您似乎在Map声明和构造中使用了非泛型Foo。取而代之的是:
Map<String, Foo> mapOfFoo = new HashMap<String, Foo>();
应该是这样的:
Map<String, Foo<String>> mapOfFoo = new HashMap<String, Foo<String>>();
然后你不必转换为String - 首先使用泛型的原因之一,而Foo#getValue()
将明确地返回一个字符串。
答案 1 :(得分:3)
这种构造在Java中实际上并不常见,问题在于泛型参数是仅编译时的特性,而映射检索是仅运行时的特性,所以没有办法编译器,以了解您的规则,而不是在某处发出警告。
实现这样的结构最安全的方法是通过一个包装类,它在逻辑上保证类型安全,你所要做的就是在getter上抛出SuppressWarnings("unchecked")
。
public class FooMapper {
private Map<Class<?>, Foo<?>> fooMap = new HashMap<>();
public <T> void setFoo(Class<T> clazz, Foo<T> foo) {
fooMap.put(clazz, foo);
}
@SuppressWarnings("unchecked")
public <T> Foo<T> getFoo(Class<T> clazz) {
return (Foo<T>) fooMap.get(clazz);
}
}
这个包装器保证你永远不会使用错误的Foo
对象放置错误类型的Class
,因此'unchecked'强制转换永远不会失败。