【问题标题】:Generic Map of Generic key/values with related types具有相关类型的通用键/值的通用映射
【发布时间】:2010-02-05 15:40:21
【问题描述】:

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

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 语句发出警告的事实只会强化这种想法。

有没有更好的方法来处理这个问题?

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

【问题讨论】:

    标签: java generics collections


    【解决方案1】:

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

    小修复:

    • &lt;V extends Object&gt; 等价于 V,后者更简洁
    • Class&lt;? extends Object&gt; 等价于 Class&lt;?&gt;,后者更简洁
    • 您可以使用@SuppressWarnings("unchecked") 注释告诉您的编译器强制转换是安全的

    【讨论】:

      【解决方案2】:

      我认为如果在某个地方没有未经检查的演员表,就无法做到这一点。您需要类似于 Haskell 的 existential types 的东西,而 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));
      }
      

      现在,如果客户端将Class&lt;FieldBinder&lt;V&gt;&gt; 传递给getInstance() 方法,您可以避免getInstance() 中的未经检查的强制转换。

      不幸的是,创建 Class&lt;FieldBinder&lt;V&gt;&gt; 本身需要未经检查的强制转换。

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

      【讨论】:

        【解决方案3】:

        RHSeeger,我收到了您最初的问题。我没有找到问题的解决方案。您可以尝试使用的是 MyMap 类,它可以根据您的要求进行绑定。然而,这张地图出现了两个问题:

        1. 因为它被声明为MyMap&lt;?&gt;,所以不能向它添加具有给定类型的东西。那是假的,我将您推荐给Java Generics FAQs(请参阅案例研究 3)了解更多详细信息。
        2. 由于map有key和value之间的联系,所以不能添加任何类型的两个独立对象(两个&lt;?&gt;指不同的类型),因为这两种类型可能没有联系。

        在玩的过程中,我看到了一些错误,我自己无法解释。我认为,一切都归结为我们尝试处理二级参数化的事实(正如我之前提到的)。

            class FieldBinder<T> {
                static class MyMap<M> extends HashMap<Class<M>, FieldBinder<M>> {
                }
                static final MyMap<?> instanceMap1 = new MyMap<Object>();
                static final Map<Class<?>, FieldBinder<?>> instanceMap2 = new HashMap<Class<?>, FieldBinder<?>>();
                public static <V> void test() {
                    Class<V> c1 = null;
                    FieldBinder<V> f1 = null;
                    Class<?> c2 = null;
                    FieldBinder<?> f2 = null;
                    instanceMap1.put(c1, f1); // error (see 1)
                    instanceMap1.put(c2, f2); // error (see 2)
                    instanceMap2.put(c1, f1); // ok
                    instanceMap2.put(c2, f2); // ok
                    instanceMap2.put(c1, f2); // wish to be an error, but ok
                    instanceMap2.put(c2, f1); // wish to be an error, but ok
                }
            }
        

        【讨论】:

        • 感谢您的详细解答。我非常了解 Java 泛型无法胜任我现在要完成的任务这一事实,而您的回答有助于巩固这一点。我想我真正想看到的是能够说.... static final 1> Map, FieldBinder1>> instanceMap2 = new 1> HashMap, 字段绑定器1>>(); .... 1> 表示“任何类型”,但将该类型绑定到可以稍后使用的变量。
        【解决方案4】:

        您参考的示例告诉您如何恢复对象的类型(类),而您需要恢复参数化的类型(类)。这是不可能的。

        【讨论】:

        • 假设我明白你在说什么,那么这根本不是我在做什么。我想要告诉编译器“这是从 'Class>' 到 'FieldBinder>' 的映射,其中两个 ? 必须相同。因此,当我使用 ?=xyz 的键拉出某些东西时,我可以安全地将值转换为 ?=xyz,因为编译器可以限制我只能以这种方式放置东西。这都是编译时信息,只是编译器似乎无法处理它。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-06-28
        • 2013-10-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多