java Java泛型传递参数
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/10684821/
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
Java generics passing parameters
提问by Ixx
Hope somebody can help me out of this confussion.
希望有人能帮助我摆脱这种困惑。
I made this method:
我做了这个方法:
public static <T> void myMethod(Map<Class<T>, MyInterface<T>> map) {
}
Used paramter T in order to make sure that the class used as key is the same as the class used as parameter in MyInterface.
使用参数 T 以确保用作键的类与用作 MyInterface 中的参数的类相同。
Now I want to pass a map which different classes as keys, of course, and corresponding implementations of MyInterface.
现在我想传递一个映射,其中不同的类作为键,当然还有 MyInterface 的相应实现。
But it doesn't work, getting syntax errors because of type parameters. Here is the code, I hope is self explanatory.
但它不起作用,因为类型参数而出现语法错误。这是代码,我希望是不言自明的。
import java.util.HashMap;
import java.util.Map;
public class Test {
public static void main(String[] args) {
Map<Class<?>, MyInterface<?>> map = new HashMap<Class<?>, MyInterface<?>>();
// Map<Class<Object>, MyInterface<Object>> map = new HashMap<Class<Object>, MyInterface<Object>>();
map.put(Object.class, new MyObjectImpl());
//if I use Map<Class<Object>, MyInterface<Object>> I get a compiler error here
//because map<String> is not map<Object> basically
map.put(String.class, new MyStringImpl());
//this would be possible using <?>, which is exactly what I don't want
// map.put(String.class, new MyIntegerImpl());
//<?> generates anyways a compiler error
myMethod(map);
}
//use T to make sure the class used as key is the same as the class of the parameter "object" in doSomething
public static <T> void myMethod(Map<Class<T>, MyInterface<T>> map) {
}
interface MyInterface<T> {
void doSomething(T object);
}
static class MyObjectImpl implements MyInterface<Object> {
@Override
public void doSomething(Object object) {
System.out.println("MyObjectImpl doSomething");
}
}
static class MyStringImpl implements MyInterface<String> {
@Override
public void doSomething(String object) {
System.out.println("MyStringImpl doSomething");
}
}
static class MyIntegerImpl implements MyInterface<Integer> {
@Override
public void doSomething(Integer object) {
System.out.println("MyIntegerImpl doSomething");
}
}
}
回答by npe
You can't do that, because there is no constraint defined in Map
's put()
method between the key
and the value
. If you want to assure that your map is populated properly (i.e. create such constraint), hide the map behind some API that will check the correctness, for example:
您不能这样做,因为在和之间Map
的put()
方法中没有定义约束。如果您想确保您的地图被正确填充(即创建此类约束),请将地图隐藏在一些将检查正确性的 API 后面,例如:key
value
public <T> void registerInterface(Class<T> clazz, MyInterface<T> intf) {
map.put(clazz, intf);
}
Then, just call the registerInterface
instead of manually populating the map.
然后,只需调用registerInterface
而不是手动填充地图。
回答by Guillaume Polet
As far as I know, you cannot declare a Map like you describe in Java. All you can do is performing type checking and/or add constraints.
据我所知,您不能像在 Java 中描述的那样声明 Map。您所能做的就是执行类型检查和/或添加约束。
Guava offers something that approaches your problem with ClassToInstanceMap. So one way to do this would be to use MapConstraints.constrainedMap
(like the example below)
Guava 提供了一些可以解决您的ClassToInstanceMap问题的方法。因此,一种方法是使用MapConstraints.constrainedMap
(如下例所示)
import java.text.ParseException;
import java.util.HashMap;
import java.util.Map;
import com.google.common.collect.MapConstraint;
import com.google.common.collect.MapConstraints;
public class Main {
interface MyInterface<T> {
void doSomething(T object);
Class<T> getType();
}
static class MyObjectImpl implements MyInterface<Object> {
@Override
public void doSomething(Object object) {
System.out.println("MyObjectImpl doSomething");
}
@Override
public Class<Object> getType() {
return Object.class;
}
}
static class MyStringImpl implements MyInterface<String> {
@Override
public void doSomething(String object) {
System.out.println("MyStringImpl doSomething");
}
@Override
public Class<String> getType() {
return String.class;
}
}
static class MyIntegerImpl implements MyInterface<Integer> {
@Override
public void doSomething(Integer object) {
System.out.println("MyIntegerImpl doSomething");
}
@Override
public Class<Integer> getType() {
return Integer.class;
}
}
public static void main(String[] args) throws ParseException {
Map<Class<?>, MyInterface<?>> map = MapConstraints.constrainedMap(new HashMap<Class<?>, Main.MyInterface<?>>(),
new MapConstraint<Class<?>, MyInterface<?>>() {
@Override
public void checkKeyValue(Class<?> key, MyInterface<?> value) {
if (value == null) {
throw new NullPointerException("value cannot be null");
}
if (value.getType() != key) {
throw new IllegalArgumentException("Value is not of the correct type");
}
}
});
map.put(Integer.class, new MyIntegerImpl());
map.put(String.class, new MyStringImpl());
map.put(Object.class, new MyObjectImpl());
map.put(Float.class, new MyIntegerImpl()); //<-- Here you will get an exception
}
}
回答by user1331740
I do not think this is possible :
我认为这是不可能的:
Class<T>
only ever accepts T.class
as value. Class<Object>
will not accept String.class
, even though Object is a superclass of String.
Class<T>
只接受T.class
作为价值。Class<Object>
不会接受String.class
,即使 Object 是 String 的超类。
For this reason any map with Class<T>
as key can have only one element, with T.class
as key value, whatever the value of T
.
出于这个原因,任何具有Class<T>
as 键的映射都只能有一个元素,具有T.class
作为键值,无论 的值是什么T
。
The compiler will only ever accept a map with a definite value of T as parameter. You cannot write Map<Class<?>, MyInterface<?>>
because each ? is assumed to be different : it does not match Map<Class<T>, MyInterface<T>>
which requires T to have the same value.
编译器只会接受具有确定 T 值的映射作为参数。你不能写,Map<Class<?>, MyInterface<?>>
因为每个?假定不同:它不匹配Map<Class<T>, MyInterface<T>>
,这要求 T 具有相同的值。
That said, myMethod will only ever accept single-entry maps, which does not seem useful.
也就是说,myMethod 将只接受单项映射,这似乎没有用。
回答by vinodn
Change your method signature to
将您的方法签名更改为
public static <T> void myMethod(Map<Class<? extends T>, MyInterface<? extends T>> map) {
}
now your declaration and invocation should work..
现在你的声明和调用应该有效..
Map<Class<?>, MyInterface<?>> map = new HashMap<Class<?>, MyInterface<?>>();
map.put(Integer.class, new MyIntegerImpl());
map.put(String.class, new MyStringImpl());
map.put(Object.class, new MyObjectImpl());
myMethod(map);