簡體   English   中英

Java:如何避免出現“不適用於自變量的方法”錯誤

[英]Java: How to avoid “method not applicable for the arguments” error

我知道已經問了無數次此類問題,但我沒有找到一個似乎可以解決和/或解釋以下問題的答案: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());
...
  }

代碼抱怨編譯錯誤:

The method getQueue(Class<BlockingQueue<T>>, UUID) in the type QueueManager<T,BlockingQueue<T>> is not applicable for the arguments (Class<LinkedBlockingQueue>, UUID)

有人可以解釋一下這里出了什么問題以及我需要做什么嗎?

我真的很想知道在哪里可以找到有關Java泛型的非常好的教程。 我看過很多資料,但它們似乎僅涵蓋使某人前進的基礎知識,而沒有涵蓋更高級的概念和更詳細的細節。

為什么要關心所管理的隊列的類型,為什么不僅僅將Supplier<BlockingQueue>傳遞給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));
    }
}

那會打電話

queueMgr.getQueue(message.getMessageHeader().getUUID(), LinkedBlockingQueue::new);

我將總結此代碼的重要部分:

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);
  }
}

請注意,在最初創建此類的實例時,C可以是任何擴展BlockingQueue的類。 但是,一旦創建了該對象,就將C設置為某種類型的特定類。 您稍后調用以下代碼:

private QueueManager<T, BlockingQueue<T>> queueMgr = new QueueManager<>();

上面的行將C定義為“ BlockingQueue”。

queueMgr.getQueue(LinkedBlockingQueue.class, message.getMessageHeader().getUUID());

但是,在此行中,您傳入了完全不同的對象。 LinkedBlockingQueue實現了BlockingQueue,是的,但是兩者的Class對象完全不同,並且它們不是由類描述指定的。 您正在尋找的是一類在方法簽名中擴展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);
  }

在此有一個微妙但重要的句法差異,希望我已清楚解釋。 您還可以通過類似的方式修改constructQueue()。 :)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM