【问题标题】:Heterogeneous Container with two element of same type具有两个相同类型元素的异构容器
【发布时间】:2013-12-31 21:22:58
【问题描述】:

我正在阅读 Effective Java - Item 29。它谈到了异构容器,在例子中:

private Map<Class<?>, Object> favorites = new HashMap<Class<?>, Object>();

public <T> void putFavirite(Class<T> type, T insance) {
    if(type == null) {
        throw new NullPointerException();
    }
    favorites.put(type, insance);

    ....
}

此模式参数化的是键而不是值,因此您不限于单一类型,不像:

 private Map<Integer, String> favorites ....    

我的问题是:如果有两个相同类型的元素需要添加到Map,即两个String,这种模式还有用吗?

【问题讨论】:

    标签: java map effective-java


    【解决方案1】:

    首先,请注意第 29 条实际上是关于使用参数化键的一般概念:

    但是,有时您需要更大的灵活性。例如,一个数据库行可以有任意多列,如果能够以类型安全的方式访问所有列,那就太好了。幸运的是,有一种简单的方法可以实现这种效果。这个想法是参数化 key 而不是 container

    本项目的目的是证明您可以通过更多方式使用泛型,而不仅仅是通过参数化类型。异构容器模式只是这种技术的一个例子。诚然,该项目可以通过一个更好的标题来更清楚地说明这一点,例如“在使用任意数量的类型时考虑使用参数化方法来强制类型安全”。

    项目演示的异构容器模式特别适用于您希望将某些类型与每种类型的特定实例相关联的情况。 Guava 包括此模式的实现及其 ClassToInstanceMap 类型 (more details)。它们还提供了更强大的TypeToInstanceMap,它支持任意泛型类型(例如List&lt;String&gt;),但API 确实略显繁琐。

    所有这一切都是说,没有什么能阻止您创建一个支持给定类型的多个实例的类似结构的类。我们可以轻松地使用 ClassToInstanceMap API 并创建一个 ClassToInstanceMultimap 类型(扩展 Guava 的 Multimap API):

    public interface ClassToInstanceMultimap<B> extends Multimap<Class<? extends B>, B> {
      /**
       * Returns the values the specified class is mapped to, or an empty collection if no
       * entries for this class is present. This will only return a value that was
       * bound to this specific class, not a value that may have been bound to a
       * subtype.
       */
      <T extends B> Collection<T> getInstances(Class<T> type);
    
      /**
       * Stores an entry mapping the specified class to the specified value. Does <i>not</i>
       *  associate this value with any of the class's supertypes.
       *
       * @return {@code true} if the method increased the size of the multimap, or
       * {@code false} if the multimap already contained the key-value pair and doesn't allow
       * duplicates
       */
      <T extends B> T putInstance(Class<T> type, T value);
    }
    

    Guava 目前不包含这样的接口,但 implementation of ClassToInstanceMap 非常简单,因此您可以轻松创建自己的 ClassToInstanceMultimap 实现。

    【讨论】:

      【解决方案2】:

      如果您放置两个字符串,第二个字符串将覆盖第一个字符串。因此,仅当需要此行为时才有用。如果您想在同一个键下存储更多对象,您可以使用其他容器,例如:

      Map<Class<?>, List<Object>>
      

      或者你可以使用 Guava 的 MultiMap:http://docs.guava-libraries.googlecode.com/git/javadoc/com/google/common/collect/Multimap.html

      或者您可以使用来自 apache commons 的 MultiMap:http://commons.apache.org/proper/commons-collections/javadocs/api-3.2.1/org/apache/commons/collections/MultiMap.html

      【讨论】:

      • List&lt;Object&gt;?那么没有类型安全,我可以说favorites.putFavirite(String.class, listOfIntegers);
      • 这个想法是有 favorites.putFavirite(Class, T) 方法 - 所以你只放一个对象,然后将其添加到列表中。检查我发布的 MultiMaps 的 API - 您可以使用此方法扩展它们。
      猜你喜欢
      • 2016-03-03
      • 1970-01-01
      • 1970-01-01
      • 2017-08-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-11-07
      相关资源
      最近更新 更多