簡體   English   中英

Java泛型傳遞參數

[英]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");
        }
    }
}

你不能這樣做,因為在keyvalue之間沒有Mapput()方法中定義的約束。 如果您想確保正確填充地圖(即創建此類約束),請隱藏一些將檢查正確性的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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM