代码之家  ›  专栏  ›  技术社区  ›  Philippe Beaudoin

如何声明具有多个具有非平凡关系的泛型类型的成员?

  •  6
  • Philippe Beaudoin  · 技术社区  · 16 年前

    private <A extends Action<R>, R extends Result> MyType<A,R> member;
    

    但是,这是无效的语法。所以我最后写了:

    private MyType<? extends Action<? extends Result>, ? extends Result> member;
    

    但这忽略了这两个类都是从 Result 都是一样的。我的类方法都强制执行这个关系,所以我可以确定MyType强制执行它,但我仍然必须不安全地进行类型转换 member

    更多细节

    private <A extends Action<R>, R extends Result> 
        Map< Class<A>, ActionHandler<A,R> > handlers;
    

    相反,我必须做:

    private Map< Class< ? extends Action<? extends Result> >, 
                 ActionHandler<? extends Action<? extends Result>, 
                               ? extends Result> > handlers;
    

    我的方法实现了所需的关系,如下所示:

    public <A extends Action<R>, R extends Result> void addHandler( 
        ActionHandler<A, R> handler ) {
      handlers.put( handler.getActionType(), handler );
    }
    

    public <A extends Action<R>, R extends Result> ActionHandler<A, R> 
        findHandler( A action ) {
      return handlers.get( action.getClass() );
    }
    

    但这不起作用:我必须添加演员阵容和 @SuppressWarnings("unchecked") .

    我试过的东西

    我试着为此创建一个新类:

    public class MyMap <A extends Action<R>, R extends Result> extends 
        HashMap< Class<A>, ActionHandler<A,R> > { ... }
    
    MyMap< ?, ? > handlers;
    

    3 回复  |  直到 16 年前
        1
  •  4
  •   David Moles paddy-p    13 年前

    没有干净的方法可以做到这一点。你能做的最好的就是你已经做过的——隐藏 Map 隐藏在强制类型安全的方法后面,并在这些方法中隐藏必要的强制转换。

    从…起 第二版,第29项:“考虑类型安全异构容器”(Josh Bloch在其中勾勒了一个更简单的版本,一个“映射”,其中键是类,值是键类的实例):

    favorites 地图很简单 Object . 换句话说 地图

    public class HandlerRegistry
    {
        private Map<Class<?>, Object> map = new HashMap<Class<?>, Object>();
    
        public <R extends Result, A extends Action<R>>
            void addHandler(Class<A> actionClass, ActionHandler<R, A> handler) {
            map.put(actionClass, handler);
        }
    
        @SuppressWarnings("unchecked")
        public <R extends Result, A extends Action<R>> ActionHandler<R, A>
            findHandler(A action) {
                return (ActionHandler<R, A>) map.get(action.getClass());
        }
    }
    

    有一件事需要注意 地图 -基于属性的解决方案:如果 action 不正是用作键的类, map.get() 不起作用——例如,如果它是一个子类,或者如果键类是一个接口和 行动 它本身就是执行。你最好是:

        @SuppressWarnings("unchecked")
        public <R extends Result, A extends Action<R>> ActionHandler<R, ? super A>
            findHandler( A action ) {
                for ( Map.Entry<Class<?>, Object> entry : map.entrySet() )
                {
                    if (entry.getKey().isAssignableFrom(action.getClass())) {
                        return (ActionHandler<R, ? super A>) entry.getValue();
                    }
                }
                return null;
        }
    

    ( 注: 最初,上面的第二个示例返回 ActionHandler<R, A> ,这实际上并不正确,应该是这样的 ? super A . (我们不知道它还能处理什么 A --它可以是任何一个超类 A. 对象 在这种特殊情况下,它可能是足够安全的,但是如果你考虑一些类似的 List ,我们可能会遇到很多麻烦:您可以安全地放置 A. 变成 List<? super A> A. ClassCastExceptions .)

        2
  •  1
  •   meriton    16 年前

    类型安全的异构容器

    有趣的谜题。

    我认为这在Java中是不可能的。考虑:

    class Entry<K,V> { 
        K key;
        V value;
    }
    interface Map<E extends Entry<?,?>> { 
        void put(E e);
        E get(Object k);
    }
    
    class MyEntry<T> extends Entry<Class<T>, T> { }
    

    手持电话的来电者 Map<MyEntry<?>> put 在Map中指定的方法很好地实现了这一点。此外, get 方法保证返回正确的映射。我无法表达的是,它的参数是返回项的键类型。

    我试着这样做:

    <K, V, RE extends E & Entry<K,V>> V get(K k);
    

    类型变量后面不能跟 其他界限

        3
  •  0
  •   Steven Schlansker    16 年前

    public class X<A, R...> {
        private Map<A,R> blah;
        public R method(A type) {}
    }