【问题标题】:Type safe heterogeneous container pattern to store lists of items键入安全的异构容器模式来存储项目列表
【发布时间】:2011-06-30 22:07:05
【问题描述】:

我正在尝试实现一个类型安全的异构容器来存储异构对象的列表。

我见过几个类型安全的异构容器模式 (link) 的例子,但它们都存储一个类型的单个对象。

我尝试如下实现:

public class EntityOrganizer {  

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

    public <T> List<T> getEntities(Class<T> clazz) {
        return entityMap.containsKey(clazz) ? entityMap.get(clazz) : Collections.EMPTY_LIST;
    }

    private <T> void addEntity(Class<T> clazz, T entity) {
        List<T> entityList = (List<T>) entityMap.get(clazz);
        if(entityList == null) {
            entityList = new ArrayList<T>();
            entityMap.put(clazz, (List<Object>) entityList);
        }
        entityList.add(entity);
    }   
}

但问题是这段代码充满了未经检查的强制转换。有人可以提供更好的实现方式吗?

非常感谢

【问题讨论】:

  • entityMap 设为Map&lt;Class&lt;?&gt;, List&lt;?&gt;&gt; 会更正确,因为这些值不是List&lt;Object&gt;,而是List&lt;various things&gt;
  • 这不是您问题的解决方案,但请考虑使用 Guava Multimap 而不是 Map
  • 我建议在 this answer 中使用 ClassToInstanceMultimap API,遵循 Guava 的 MultimapClassToInstanceMap 类型。

标签: java design-patterns generics


【解决方案1】:

问题是,什么是“未经检查的演员表”?

有时可以证明强制转换是安全的,不幸的是,证明超出了 javac 的能力,它只做规范中列举的有限静态分析。但是程序员比javac聪明。

在这种情况下,我认为这些是“已检查的强制转换”,并且取消警告非常合适。

查看其他 2 个相关示例:

Heterogeneous container to store genericly typed objects in Java

Typesafe forName class loading

【讨论】:

    【解决方案2】:

    你不必投射:

    (List&lt;T&gt;) entityMap.get(clazz).

    当你说

    entityMap.get(clazz)

    您实际上有一个List&lt;Object&gt;,足以满足您的需求。

    entityList = new ArrayList&lt;T&gt;();

    你应该只使用entityList = new ArrayList&lt;Object&gt;();

    您的类型安全由方法声明确保

    <T> void addEntity(Class<T> clazz, T entity) {
    

    以及使用以 Class 作为键的 Map。

    所以代码应该是这样的:

     private <T> void addEntity(Class<T> clazz, T entity) {
                List<Object> entityList = entityMap.get(clazz);
                if(entityList == null) {
                    entityList = new ArrayList<Object>();
                    entityMap.put(clazz, entityList);
                }
                entityList.add(entity);
       } 
    

    【讨论】:

      【解决方案3】:

      对于非常小的列表,您可以对 java 泛型的链表进行编码。

      And<UUID, And<Integer, Of<String>>> x = Tuple.of("test").and(2).and(UUID.randomUUID());
      

      AndOf 的类型定义有点让人费解。为简洁起见,我省略了 equals/hashCode。

      import java.util.Objects;
      import java.util.UUID;
      
      public abstract class Tuple<T extends Tuple<T>> {
          public static final <E> Of<E> of(E e) {
              return new Of<>(e);
          }
      
          public abstract <E> And<E, T> and(E e);
      
          public static final class And<T, R extends Tuple<R>> extends Tuple<And<T, R>> {
              public final T t;
              public final R r;
      
              private And(T t, R rest) {
                  this.t = t;
                  this.r = rest;
              }
      
              public <N> And<N, And<T, R>> and(N next) {
                  return new And<>(next, this);
              }
          }
      
          public static final class Of<T> extends Tuple<Of<T>> {
              public final T t;
      
              private Of(T t) {
                  this.t = t;
              }
      
              public <N> And<N, Of<T>> and(N next) {
                  return new And<>(next, this);
              }
          }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-02-24
        • 1970-01-01
        • 2016-01-14
        • 1970-01-01
        • 2018-06-07
        相关资源
        最近更新 更多