Java:如何避免;方法不适用于参数;错误

Java:如何避免;方法不适用于参数;错误,java,generics,Java,Generics,我意识到这类问题已经被问过无数次了,但我还没有找到一个答案来解决和/或解释1)我做错了什么,2)我需要做什么来纠正它 我有一个应用程序,试图在其中管理队列集合。队列管理器的用户将通过提供唯一ID来请求队列,如果队列已被管理,则队列管理器将返回队列;如果尚未创建,则创建新队列(通过反射)并返回队列 我已经将队列管理器编码为使用Java泛型,但遇到了一个我不理解的问题,也不知道如何纠正这个问题 以下是队列管理器: public class QueueManager<T extends Mess

我意识到这类问题已经被问过无数次了,但我还没有找到一个答案来解决和/或解释1)我做错了什么,2)我需要做什么来纠正它

我有一个应用程序,试图在其中管理队列集合。队列管理器的用户将通过提供唯一ID来请求队列,如果队列已被管理,则队列管理器将返回队列;如果尚未创建,则创建新队列(通过反射)并返回队列

我已经将队列管理器编码为使用Java泛型,但遇到了一个我不理解的问题,也不知道如何纠正这个问题

以下是队列管理器:

public class QueueManager<T extends MessageType, C extends BlockingQueue<T>> {

  private Map<UUID, C> queueMap;

  public void removeQueue(UUID id) {
    queueMap.remove(id);
  }

  public C getQueue(Class<C> clazz, UUID id) {
    if (!queueMap.containsKey(id)) {
      queueMap.put(id, constructQueue(clazz));
    }

    return queueMap.get(id);
  }

  private C constructQueue(Class<C> clazz) {
    C result = null;

    try {
      Constructor<C> constructor = clazz.getDeclaredConstructor();
      result = constructor.newInstance();
    } catch (NoSuchMethodException | SecurityException | InstantiationException
        | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
      // handle exception
    }

    return result;
  }

}
public class QueueingListener<T extends MessageType> implements MessageListener<T> {

  private QueueManager<T, BlockingQueue<T>> queueMgr = new QueueManager<>();
...
  @Override
  public void handleMessage(T message) {
...
      queueMgr.getQueue(LinkedBlockingQueue.class,
          message.getMessageHeader().getUUID());
...
  }
公共类队列管理器{
私有映射;
公共无效移除队列(UUID id){
queueMap.remove(id);
}
公共C getQueue(类clazz,UUID id){
如果(!queueMap.containsKey(id)){
put(id,constructQueue(clazz));
}
返回queueMap.get(id);
}
专用C构造队列(clazz类){
C结果=空;
试一试{
构造函数=clazz.getDeclaredConstructor();
result=constructor.newInstance();
}catch(NoSuchMethodException | SecurityException |实例化Exception
|IllegalAccessException | IllegalArgumentException | InvocationTargetException e){
//处理异常
}
返回结果;
}
}
使用队列管理器的代码:

public class QueueManager<T extends MessageType, C extends BlockingQueue<T>> {

  private Map<UUID, C> queueMap;

  public void removeQueue(UUID id) {
    queueMap.remove(id);
  }

  public C getQueue(Class<C> clazz, UUID id) {
    if (!queueMap.containsKey(id)) {
      queueMap.put(id, constructQueue(clazz));
    }

    return queueMap.get(id);
  }

  private C constructQueue(Class<C> clazz) {
    C result = null;

    try {
      Constructor<C> constructor = clazz.getDeclaredConstructor();
      result = constructor.newInstance();
    } catch (NoSuchMethodException | SecurityException | InstantiationException
        | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
      // handle exception
    }

    return result;
  }

}
public class QueueingListener<T extends MessageType> implements MessageListener<T> {

  private QueueManager<T, BlockingQueue<T>> queueMgr = new QueueManager<>();
...
  @Override
  public void handleMessage(T message) {
...
      queueMgr.getQueue(LinkedBlockingQueue.class,
          message.getMessageHeader().getUUID());
...
  }
公共类QueueingListener实现MessageListener{
private QueueManager queueMgr=new QueueManager();
...
@凌驾
公共无效handleMessage(T消息){
...
queueMgr.getQueue(LinkedBlockingQueue.class,
message.getMessageHeader().getUUID());
...
}
代码出现编译错误:

The method getQueue(Class<BlockingQueue<T>>, UUID) in the type QueueManager<T,BlockingQueue<T>> is not applicable for the arguments (Class<LinkedBlockingQueue>, UUID)
类型QueueManager中的方法getQueue(Class,UUID)不适用于参数(Class,UUID)
有人能解释一下这里出了什么问题以及我需要做什么吗


我真的很想知道在哪里可以找到一本关于Java泛型的非常好的教程。我看了很多资料,但它们似乎只涵盖了让人开始学习的基础知识,而没有涵盖更高级的概念和更精细的细节。

为什么要关心所管理的队列类型,为什么不把一个
供应商
传递给getter呢

public class QueueManager<T extends MessageType> {

    private Map<UUID, BlockingQueue<T>> queueMap;

    public void removeQueue(UUID id) {
      queueMap.remove(id);
    }

    public BlockingQueue<T> getQueue(UUID id, Supplier<BlockingQueue<T>> createQueue) {
        return queueMap.computeIfAbsent(id, k -> createQueue.get());
    }

    // let's add a default while we're at it 
    public BlockingQueue<T> getQueue(UUID id) {
        return getQueue(id, () -> new ArrayBlockingQueue<T>(50));
    }
}

为什么要关心所管理的队列类型,为什么不将
供应商
传递给getter

public class QueueManager<T extends MessageType> {

    private Map<UUID, BlockingQueue<T>> queueMap;

    public void removeQueue(UUID id) {
      queueMap.remove(id);
    }

    public BlockingQueue<T> getQueue(UUID id, Supplier<BlockingQueue<T>> createQueue) {
        return queueMap.computeIfAbsent(id, k -> createQueue.get());
    }

    // let's add a default while we're at it 
    public BlockingQueue<T> getQueue(UUID id) {
        return getQueue(id, () -> new ArrayBlockingQueue<T>(50));
    }
}

我将总结这段代码的重要部分,以说明我要提出的观点:

public class QueueManager<T extends MessageType, C extends BlockingQueue<T>> {
  public C getQueue(Class<C> clazz, UUID id) {
    if (!queueMap.containsKey(id)) {
      queueMap.put(id, constructQueue(clazz));
    }

    return queueMap.get(id);
  }
}
但是,在这一行中,您传入了一个完全不同的对象。LinkedBlockingQueue实现了BlockingQueue,是的,但是这两个对象的类对象完全不同,它们不是由类描述指定的。您要找的是一个扩展了C的类在方法签名中。因此,纠正此错误的方法是修改getQueue()方法,如下所示:

  public <X extends C> C getQueue(Class<X> clazz, UUID id) {
    if (!queueMap.containsKey(id)) {
      queueMap.put(id, constructQueue(clazz));
    }

    return queueMap.get(id);
  }
public getQueue(类clazz,UUID-id){
如果(!queueMap.containsKey(id)){
put(id,constructQueue(clazz));
}
返回queueMap.get(id);
}

这里有一个微妙但重要的语法差异,我希望我已经解释清楚了。您还可以用类似的方式修改constructQueue()。)

我将总结这段代码中的重要部分,以说明我要说的要点:

public class QueueManager<T extends MessageType, C extends BlockingQueue<T>> {
  public C getQueue(Class<C> clazz, UUID id) {
    if (!queueMap.containsKey(id)) {
      queueMap.put(id, constructQueue(clazz));
    }

    return queueMap.get(id);
  }
}
但是,在这一行中,您传入了一个完全不同的对象。LinkedBlockingQueue实现了BlockingQueue,是的,但是这两个对象的类对象完全不同,它们不是由类描述指定的。您要找的是一个扩展了C的类在方法签名中。因此,纠正此错误的方法是修改getQueue()方法,如下所示:

  public <X extends C> C getQueue(Class<X> clazz, UUID id) {
    if (!queueMap.containsKey(id)) {
      queueMap.put(id, constructQueue(clazz));
    }

    return queueMap.get(id);
  }
public getQueue(类clazz,UUID-id){
如果(!queueMap.containsKey(id)){
put(id,constructQueue(clazz));
}
返回queueMap.get(id);
}

这里有一个微妙但重要的语法差异,我希望我已经解释清楚了以类似的方式:

你为什么不把一个
供应商
传递给
获取队列
而不是类,然后通过反射构造它呢?@daniu请详细说明。你为什么不把
供应商
传递给
获取队列
而不是类,然后通过反射构造它呢?@daniu请详细说明。