具有相关类型的泛型键/值的泛型映射

2022-09-03 13:38:26

我正在尝试创建一个泛型类型,该类型保留已创建的版本本身的映射以供以后使用。实际上,它是一种单例模式,其中每种类型都有一个实例。到目前为止,我的代码是:

public class FieldBinder<T> {
    static final Map<Class<? extends Object>,FieldBinder<? extends Object>> instanceMap = 
        new HashMap<Class<? extends Object>,FieldBinder<? extends Object>>();

    private FieldBinder() {}

    synchronized public static <V extends Object> FieldBinder<V> getInstance(Class<V> klass) {
        if(!instanceMap.containsKey(klass)) {
            instanceMap.put(klass, new FieldBinder<V>());
        }
        return (FieldBinder<V>)instanceMap.get(klass);
    }
}

但是,我仍然不确定我是否“做得对”。感觉我应该能够指定集合是(类-> FieldBinder)。IDE 对 return 语句发出警告这一事实只会强化这一想法。

有没有更好的方法来解决这个问题?

注意:这个问题似乎密切相关,但距离足够远,以至于我无法弄清楚如何将其中的信息应用于我自己的问题。


答案 1

您的实现是正确的。没有“更好”的方法可以做到这一点(如果代码中有这样的事情是“更好”的,这是另一个问题。

小修复:

  • <V extends Object>等效于 哪个不那么详细V
  • Class<? extends Object>等效于 哪个不那么详细Class<?>
  • 您可以使用注释告诉编译器强制转换是安全的@SuppressWarnings("unchecked")

答案 2

我不认为在没有不受检查的演员的情况下可以做到这一点。你需要一些类似于Haskell的存在类型的东西,而Java没有。

您可以让客户端改为执行未经检查的强制转换...

synchronized public static <V> FieldBinder<V>
getInstance(Class<V> klass, Class<FieldBinder<V>> binderKlass) {
    if(!instanceMap.containsKey(klass)) {
        instanceMap.put(klass, new FieldBinder<V>());
    }
    return binderKlass.cast(instanceMap.get(klass));
}

现在,如果客户端将 a 传递给该方法,则可以避免 在 中进行未经检查的强制转换。Class<FieldBinder<V>>getInstance()getInstance()

不幸的是,创建自身需要不受检查的强制转换。Class<FieldBinder<V>>

Class<FieldBinder<Integer>> binderKlass =
    (Class<FieldBinder<Integer>>) (Class<?>) FieldBinder.class;
BinderAssociator.getInstance(Integer.class, binderKlass);