[英]Java generics passing parameters
希望有人可以帮助我摆脱这种困扰。
我做了这个方法:
public static <T> void myMethod(Map<Class<T>, MyInterface<T>> map) {
}
使用参数T以确保用作键的类与用作MyInterface中的参数的类相同。
现在我想传递一个不同类作为键的映射,当然还有MyInterface的相应实现。
但它不起作用,因类型参数而导致语法错误。 这是代码,我希望是自我解释。
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");
}
}
}
你不能这样做,因为在key
和value
之间没有Map
的put()
方法中定义的约束。 如果您想确保正确填充地图(即创建此类约束),请隐藏一些将检查正确性的API后面的地图,例如:
public <T> void registerInterface(Class<T> clazz, MyInterface<T> intf) {
map.put(clazz, intf);
}
然后,只需调用registerInterface
而不是手动填充地图。
据我所知,你不能像在Java中描述的那样声明一个Map。 您所能做的就是执行类型检查和/或添加约束。
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
}
}
我不认为这是可能的:
Class<T>
只接受T.class
作为值。 Class<Object>
不接受String.class
,即使Object是String的超类。
因此,任何以Class<T>
为键的映射都只能有一个元素, T.class
作为键值,无论T
的值如何。
编译器只会接受一个定义值为T的映射作为参数。 你不能写Map<Class<?>, MyInterface<?>>
因为每个? 假设是不同的:它与Map<Class<T>, MyInterface<T>>
不匹配Map<Class<T>, MyInterface<T>>
后者要求T具有相同的值。
也就是说,myMethod只接受单入口地图,这似乎没用。
将方法签名更改为
public static <T> void myMethod(Map<Class<? extends T>, MyInterface<? extends T>> map) {
}
现在你的声明和调用应该工作..
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.