单个引用的Java Map

时间:2014-04-19 15:43:18

标签: java

我想创建一个单例类的地图,我可以通过交叉引用访问它以响应特定的请求。我已经实现了以下功能,但是无法获得可以调用getInstance()的实际引用。

Map<Integer, Class<? extends Thing>> xref = new HashMap<Integer, Class<? extends Thing>>();
xref.put(1, ThingOne.class);
xref.put(2, ThingTwo.class);

Class<? extends Thing> t = xref.get(1);

最终做一些像......

something.perform(arg1, arg2);

无法弄清楚如何从“t”到“某事”,或者如果按照我编码的方式可行。我尝试调用.cast(Thing.class).getInstance(),但得到了一个Cast异常。还试过反射来获取getInstance()方法,但也没有运气。

可能是我完全走错了路。给定1..n个可能的函数,解决方案的任何给定实例可能仅需要这些的子集。另外,我想在启动时轻松添加/删除类并通过配置管理接口与一堆对象实例化。

谢谢!

1 个答案:

答案 0 :(得分:0)

我不太了解您创建此地图的目的。从你所写的内容来看,似乎你可以简单地在每个相关的类上放置返回单例的静态getInstance()方法。或者更简单:将每个共享实例作为其类的静态最终字段。

如果必须使用地图,请勿使用整数作为关键字。类是键,它的实例是值。类似的东西:

private static final Map<Class<?>,Object> singletons = new HashMap<>();

public static synchronized <T> T getSingleton(Class<T> klass) {
    Object obj = singletons.get(klass);
    if (obj == null) {
        try {
            obj = klass.newInstance();
        } catch (InstantiationException | IllegalAccessException e) {
            throw new RuntimeException(e);
        }
        singletons.put(klass, obj);
    }
    return klass.cast(obj);
}

那里的创建代码很狡猾,需要一个公共的无参数构造函数。您也可以通过反射在每个类上调用一个静态的,特别命名的方法来创建所需的实例(“createInstance”),这可能会更灵活一些,但是当你这样做时,它再次询问为什么要打扰地图,什么时候可以直接在类上调用方法?

地图的一个有趣的可能性是提供创建实例的功能。在Java 8语法中(导入java.util.function.Supplier):

private static final Map<Class<?>,Object> singletons = new HashMap<>();

public static synchronized <T> T getSingleton(Class<T> klass) {
    Object obj = singletons.get(klass);
    if (obj instanceof Supplier) {
        obj = ((Supplier<?>)obj).get();
        singletons.put(klass, obj);
    }
    return klass.cast(obj);
}

public static synchronized <T> void declareSingleton(Class<T> klass, Supplier<T> supplier) {
    if (Supplier.class.isAssignableFrom(klass)) {
        // prevent Supplier<Supplier<?>> weirdness;
        // could use separate maps if those are really needed
        throw new UnsupportedOperationException();
    }
    singletons.put(klass, supplier);
}

static {
    // add creation expressions for several classes;
    // instances will not be created until needed
    declareSingleton(ThingOne.class, () -> new ThingOne());
    declareSingleton(ThingTwo.class, () -> new ThingTwo(123));
}

我不确定这是否是你想要的,但它可能包含一些想法。

编辑:我刚刚意识到使用Class本身作为键的问题:即使在特定程序运行期间不需要类,它也会导致加载类。使用String键可以避免加载不需要的类,但会增加脆弱性。这是另一个反对使用地图的论据。