簡體   English   中英

為什么Java不能使用泛型類型參數推斷lambda表達式的類型?

[英]Why can't Java infer the type of a lambda expression with a generic type parameter?

給出以下代碼:

abstract class Event {
}

class MyEvent extends Event {
}

interface EventSubscriber<T extends Event> {

  void onMessage(T message);

  Class<T> getMessageType();
}

interface MyEventSubscriber extends EventSubscriber<MyEvent> {

  @Override
  default Class<MyEvent> getMessageType() {
    return MyEvent.class;
  }
}

class SubscriberManager {

  public void subscribe(EventSubscriber<? extends Event> subscriber) {
  }
}

我想通過調用getMessageType方法來訪問事件訂閱者持有的泛型類型參數。 我還想通過將lambda表達式傳遞給subscribe方法來使用SubscriberManager

subscriberManager.subscribe((MyEvent event) -> {});

遺憾的是,Java編譯器無法推斷傳遞給subscribe方法的lambda表達式的類型,盡管我很明顯lambda的類型可以從lambda的參數 - MyEvent - > MyEventSubscriber推導出來。 Java編譯器給我以下錯誤:

不兼容的類型:EventSubscriber不是一個功能接口,在接口EventSubscriber中找到多個非重寫的抽象方法

所以我需要指定lambda表達式的類型或使用匿名類來繞過這個限制:

MyEventSubscriber myEventSubscriber = (MyEvent event) -> {};
subscriberManager.subscribe(myEventSubscriber);

subscriberManager.subscribe(new MyEventSubscriber() {
  @Override
  public void onMessage(MyEvent message) {

  }
});

我可以向SubscriberManager類添加一個重載方法,從EventSubscriber接口中刪除getMessageType方法(因為我們知道訂閱者的實際類型,因此知道它保存的消息類型)並使用我在第一個代碼中提到的簡單lambda表達式例如,但它會使整個代碼更少'多態'我猜:

class SubscriberManager {

  public void subscribe(EventSubscriber<? extends Event> subscriber) {
  }

  public void subscribe(MyEventSubscriber subscriber) {
  }
}

問題是您的EventSubscriber接口不是功能接口,因為錯誤告訴您:有兩種方法可以實現。 事實上,你已經創建了一個名為MyEventSubscriber的實際功能接口,這意味着你希望java以某種方式直覺知道它存在。

Java並不是要在類路徑中搜索數百萬個類,而只是為了查看整個混亂中是否存在可能有效或無效的內容。 我希望通過這樣的方式顯然為什么會這樣,以及為什么它永遠不會那樣工作。

具體來說:因為有一個lambda,java需要定位它的類型。 為此,java首先檢查lambda周圍的上下文:它檢查名為subscribe的各種方法,並且通知只有一個,它需要一個類型為EventSubscriber的參數。 然后它將lambda目標類型化為此類型,並立即失敗,因為它不是一個功能接口。 編譯器無法弄明白它應該是MyEventSubscriber目標類型。

我做了一些使用反射檢查實際類型的玩具,但這不起作用; 你必須找到解決這個問題的另一種方法。

暫無
暫無

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

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