传递参数的Java泛型

传递参数的Java泛型,java,generics,Java,Generics,希望有人能帮我摆脱这种困惑 我提出了这个方法: public static <T> void myMethod(Map<Class<T>, MyInterface<T>> map) { } publicstaticvoidmymethod(Map){ } 使用参数T以确保用作键的类与MyInterface中用作参数的类相同 现在我想传递一个映射,其中不同的类作为键,当然,还有MyInterface的相应实现 但它不起作用,因为类型参数而导致语法

希望有人能帮我摆脱这种困惑

我提出了这个方法:

public static <T> void myMethod(Map<Class<T>, MyInterface<T>> map) {
}
publicstaticvoidmymethod(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");
        }
    }
}
import java.util.HashMap;
导入java.util.Map;
公开课考试{
公共静态void main(字符串[]args){
Map>Map=newhashmap>();
//Map Map=newhashmap();
put(Object.class,新的MyObjectImpl());
//如果我使用Map,我会在这里得到一个编译器错误
//因为地图基本上不是地图
put(String.class,新的MyStringImpl());
//这将是可能的使用,这正是我不想要的
//put(String.class,新的MyIntegerImpl());
//无论如何都会生成一个编译器错误
myMethod(map);
}
//使用T确保用作键的类与doSomething中参数“object”的类相同
公共静态void myMethod(映射){
}
接口MyInterface{
无效剂量测定(T对象);
}
静态类MyObjectImpl实现MyInterface{
@凌驾
公共void doSomething(对象){
System.out.println(“MyObjectImpl doSomething”);
}
}
静态类MyStringImpl实现MyInterface{
@凌驾
公共void doSomething(字符串对象){
System.out.println(“MyStringImpl doSomething”);
}
}
静态类MyIntegerImpl实现MyInterface{
@凌驾
公共void doSomething(整数对象){
System.out.println(“MyIntegerImpl doSomething”);
}
}
}

我认为这是不可能的:

Class
仅接受
T.Class
作为值<代码>类将不接受
字符串。类
,即使对象是字符串的超类

因此,任何键为
Class
的映射只能有一个元素,键值为
T.Class
的映射,无论
T
的值是多少

编译器将只接受具有确定值T作为参数的映射。您无法写入
映射>
,因为每个映射都是?假设不同:它与要求T具有相同值的映射不匹配


这就是说,myMethod将只接受单条目映射,这似乎并不有用。

将您的方法签名更改为

public static <T> void myMethod(Map<Class<? extends T>, MyInterface<? extends T>> map) {

}

publicstaticvoidmymethod(Map您不能这样做,因为
Map
put()
方法在
键和
值之间没有定义约束。如果您想确保正确填充映射(即创建这样的约束),将地图隐藏在将检查正确性的API后面,例如:

public <T> void registerInterface(Class<T> clazz, MyInterface<T> intf) {
    map.put(clazz, intf);
}
公共无效注册表接口(clazz类,MyInterface intf){
地图放置(clazz,intf);
}

然后,只需调用
registerInterface
而不是手动填充映射。

据我所知,您不能像Java中描述的那样声明映射。您所能做的就是执行类型检查和/或添加约束

Guava提供了一些解决您问题的方法。因此,一种方法是使用
MapConstraints.constrainedMap
(如下面的示例)

import java.text.ParseException;
导入java.util.HashMap;
导入java.util.Map;
导入com.google.common.collect.MapConstraint;
导入com.google.common.collect.MapConstraints;
公共班机{
接口MyInterface{
无效剂量测定(T对象);
类getType();
}
静态类MyObjectImpl实现MyInterface{
@凌驾
公共void doSomething(对象){
System.out.println(“MyObjectImpl doSomething”);
}
@凌驾
公共类getType(){
返回Object.class;
}
}
静态类MyStringImpl实现MyInterface{
@凌驾
公共void doSomething(字符串对象){
System.out.println(“MyStringImpl doSomething”);
}
@凌驾
公共类getType(){
返回字符串.class;
}
}
静态类MyIntegerImpl实现MyInterface{
@凌驾
公共void doSomething(整数对象){
System.out.println(“MyIntegerImpl doSomething”);
}
@凌驾
公共类getType(){
返回Integer.class;
}
}
公共静态void main(字符串[]args)引发异常{
Map>Map=MapConstraints.constrainedMap(新HashMap>()),
新映射约束>(){
@凌驾
public void checkKeyValue(类键,MyInterface值){
如果(值==null){
抛出新的NullPointerException(“值不能为null”);
}
if(value.getType()!=key){
抛出新的IllegalArgumentException(“值的类型不正确”);
}
}
});
put(Integer.class,新的MyIntegerImpl());
put(String.class,新的MyStringImpl());
put(Object.class,新的MyObjectImpl());

map.put(Float.class,new MyIntegerImpl());//以
Impl
结尾的类名通常是过度工程化的症状(例如,它意味着给定接口只有一个实现,无法强制实施)。算了吧,这是行不通的。泛型只能定义同质映射。您不能对条目强制任何内容
public <T> void registerInterface(Class<T> clazz, MyInterface<T> intf) {
    map.put(clazz, intf);
}
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
    }
}