使用接口Class <T>作为键来获取具体的实例值?

cod*_*edd 9 java generics inheritance hashmap

我有以下测试用例无法从以下位置检索值Map:

package tests;

import java.util.HashMap;
import java.util.Map;

public class ClassTest {

    interface A {}
    interface B extends A {}
    interface C extends A {}

    class D implements B {}
    class E implements C {}

    public ClassTest() {
        Map<Class<? extends A>, A> map = new HashMap<>();

        A d = new D();
        A e = new E();

        map.put(d.getClass(), d);
        map.put(e.getClass(), e);

        System.out.println(B.class.getSimpleName() + ": " + map.get(B.class));
        System.out.println(C.class.getSimpleName() + ": " + map.get(C.class));
    }

    public static void main(String[] args) {
        new ClassTest();
    }

}
Run Code Online (Sandbox Code Playgroud)

预计产量为:

B: D
C: E
Run Code Online (Sandbox Code Playgroud)

实际的输出是:

B: null
C: null
Run Code Online (Sandbox Code Playgroud)

根据我的理解,案例是"预期"失败因为B.class不等于D.class,即使Dclass是B接口的实现...因此map.get(...)无法找到关联键的实例值.(纠正我,如果我错了这一点.)上述希望的情况下,显示了意图的背后是什么我要完成和"精神".

有没有一个好的/优雅的替代方案,但也保留了我试图做的精神?

我正在更新代码以替换Class<T>用作类型标记的"开放集"的枚举类型,有点类似于Effective Java,2nd Ed.,Item 29.


正如@CKing在评论中所要求的那样,本书的部分内容引用了我的方法.

客户端Class在设置和获取收藏夹时会显示一个对象.这是API:

// Typesafe heterogeneous container pattern - API
public class Favorites {
    public <T> void putFavorite(Class<T> type, T instance);
    public <T> T getFavorite(Class<T> type);
}
Run Code Online (Sandbox Code Playgroud)

下面是行使一个示例程序Favorites类,存储,检索和打印最喜欢的String,IntegerClass 实例:

// Typesafe heterogeneous container pattern - client
public static void main(String[] args) {
    Favorites f = new Favorites();

    f.putFavorite(String.class, "Java");
    f.putFavorite(Integer.class, 0xcafebabe);
    f.putFavorite(Class.class, Favorites.class);

    String favoriteString = f.getFavorite(String.class);
    int favoriteInteger = f.getFavorite(Integer.class);
    Class<?> favoriteClass = f.getFavorite(Class.class);
    System.out.printf("%s %x %s%n", favoriteString, favoriteInteger, favoriteClass.getName());
}
Run Code Online (Sandbox Code Playgroud)

正如您所料,该程序打印出来Java cafebabe Favorites.

请理解我知道这本书的例子是有效的,因为它使用了值的具体具体类(例如String.class,对于实际的String,而不是某些假设的派生类型String等)如上所述,这只是激发了我的方法,看看我的测试用例会工作,现在我正在寻找一个解决方案或替代方案,尊重我打算在测试用例上做的"精神".

Vla*_*nin 0

也许不是那么优雅,但您可以使用反射来获取所有可分配的值Key.class

System.out.println(B.class.getSimpleName() + ": " + getMapEntries(map, B.class));
System.out.println(C.class.getSimpleName() + ": " + getMapEntries(map, C.class));

....

private <T extends A> List<T> getMapEntries(Map<Class<? extends A>, A> map, Class<T> clazz) {
    List<T> result = new ArrayList<>();
    for (Map.Entry<Class<? extends A>, A> entry : map.entrySet()) {
        if (clazz.isAssignableFrom(entry.getKey())) {
            result.add((T) entry.getValue());
        }
    }
    return result;
}
Run Code Online (Sandbox Code Playgroud)