Java泛型类型在方法签名中不匹配

时间:2013-11-03 01:46:20

标签: java generics

我有一个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>相同,所以我有点困惑。还有更好的选择吗?

2 个答案:

答案 0 :(得分:3)

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

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声明了一个类型参数Executor,然后将其用作_keys_service的类型参数,确保它们兼容。< / p>

如果您无法参数化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();
    }
}

答案 1 :(得分:2)

最终分配时

IService<?> _service;

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

最终分配时

KeyList<?> _keys;

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

没有什么说这些类型是兼容的,因此编译器不允许它。这与Capture Conversion

有关
  

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

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

一个丑陋的解决方案是简单地删除通配符类型声明

KeyList _keys;
IService _service;

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