2

我有一个使用参数Executor调用接口实例的类。IService<T>KeyList<T>

   class Executor{
      KeyList<?> _keys;
      IService<?> _service;
      public Executor(IService<?> service, KeyList<?> keys){
         _service = service;
         _keys = keys;
      }

      public void execute(){
         _service.invoke(_keys);
      }
   }

   interface IService<T>{
      public void invoke( KeyList<T> keys);
   }

   class KeyList<T> {
      List<T> _list;
   }

我使用<?>了 Executor 的成员,因为它不关心 IService 和 KeyList 是如何参数化的,但是下面会引发编译错误,说明参数不适用:

 public void execute(){
    _service.invoke(_keys); //error on invoke
 }

我猜这是在抱怨,因为KeyList<?>不等于KeyList<T>,但<?>等于<? extends Object>,所以我有点困惑。有更好的选择吗?

4

2 回答 2

3

通配符( ?) 表示某些特定的未知类型。但是您在这里处理两个单独的通配符 - 它们可能不一样。请改用以下内容:

class Executor<T> {
    KeyList<T> _keys;
    IService<T> _service;
    public Executor(IService<T> service, KeyList<T> keys){
        _service = service;
        _keys = keys;
    }

    public void execute(){
        _service.invoke(_keys);
    }
}

T这为 class声明了一个类型参数Executor,然后将其用作_keysand的类型参数_service,确保它们兼容。

如果您不能 parameterize Executor,请尝试使用参数化辅助类:

class Executor {

    private static final class ServiceAndKeys<T> {

        private final KeyList<T> keys;
        private final IService<T> service;

        ServiceAndKeys(IService<T> service, KeyList<T> keys) {
            this.service = service;
            this.keys = keys;
        }

        void execute() {
            service.invoke(keys);
        }
    }

    private final ServiceAndKeys<?> serviceAndKeys;

    public <T> Executor(IService<T> service, KeyList<T> keys){
        serviceAndKeys = new ServiceAndKeys<T>(service, keys);
    }

    public void execute() {
        serviceAndKeys.execute();
    }
}
于 2013-11-03T01:52:48.237 回答
2

当你最终分配

IService<?> _service;

它会有一些类型。考虑一下这个type-1

当你最终分配

KeyList<?> _keys;

它会有一些类型。考虑一下这个type-2

没有说这些类型是兼容的,因此编译器不允许这样做。这与捕获转换有关。

如果 Ti 是 ? 形式的通配符类型参数(第 4.5.1 节),则 Si 是一个新类型变量,其上限为 Ui[A1:=S1,...,An:=Sn],下限为空类型(§4.1)。

因此,每个<?>都是不同的类型变量。

一个丑陋的解决方案是完全删除通配符类型声明

KeyList _keys;
IService _service;

但是您可能会在运行时遇到其他麻烦。

于 2013-11-03T01:50:52.380 回答