[英]Java generics passing parameters
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");
}
}
}
You can't do that, because there is no constraint defined in Map
's put()
method between the key
and the value
. 你不能这样做,因为在
key
和value
之间没有Map
的put()
方法中定义的约束。 If you want to assure that your map is populated properly (ie create such constraint), hide the map behind some API that will check the correctness, for example: 如果您想确保正确填充地图(即创建此类约束),请隐藏一些将检查正确性的API后面的地图,例如:
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
而不是手动填充地图。
As far as I know, you cannot declare a Map like you describe in Java. 据我所知,你不能像在Java中描述的那样声明一个Map。 All you can do is performing type checking and/or add constraints.
您所能做的就是执行类型检查和/或添加约束。
Guava offers something that approaches your problem with ClassToInstanceMap . Guava提供了一些可以通过ClassToInstanceMap解决问题的方法。 So one way to do this would be to use
MapConstraints.constrainedMap
(like the example below) 所以这样做的一种方法是使用
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
}
}
I do not think this is possible : 我不认为这是可能的:
Class<T>
only ever accepts T.class
as value. Class<T>
只接受T.class
作为值。 Class<Object>
will not accept String.class
, even though Object is a superclass of String. 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>
为键的映射都只能有一个元素, T.class
作为键值,无论T
的值如何。
The compiler will only ever accept a map with a definite value of T as parameter. 编译器只会接受一个定义值为T的映射作为参数。 You cannot write
Map<Class<?>, MyInterface<?>>
because each ? 你不能写
Map<Class<?>, MyInterface<?>>
因为每个? is assumed to be different : it does not match Map<Class<T>, MyInterface<T>>
which requires T to have the same value. 假设是不同的:它与
Map<Class<T>, MyInterface<T>>
不匹配Map<Class<T>, MyInterface<T>>
后者要求T具有相同的值。
That said, myMethod will only ever accept single-entry maps, which does not seem useful. 也就是说,myMethod只接受单入口地图,这似乎没用。
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);
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.