С учетом следующего кода:
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
.
Я также хотел бы использовать SubscriberManager
, передавая лямбда-выражения в метод subscribe
:
subscriberManager.subscribe((MyEvent event) -> {});
К сожалению, компилятор Java не может определить тип лямбда-выражения, которое передается методу subscribe
, хотя для меня совершенно очевидно, что тип лямбда-выражения может быть выведен из аргумента лямбды - MyEvent
-> MyEventSubscriber
. Компилятор Java выдает мне следующую ошибку:
несовместимые типы: EventSubscriber не является функциональным интерфейсом
несколько не переопределяющих абстрактных методов, найденных в интерфейсе EventSubscriber
Поэтому мне нужно указать тип лямбда-выражения или использовать анонимный класс, чтобы обойти это ограничение:
MyEventSubscriber myEventSubscriber = (MyEvent event) -> {};
subscriberManager.subscribe(myEventSubscriber);
subscriberManager.subscribe(new MyEventSubscriber() {
@Override
public void onMessage(MyEvent message) {
}
});
Я мог бы добавить перегруженный метод в класс SubscriberManager
, удалить метод getMessageType
из интерфейса EventSubscriber
(так как мы знали бы фактический тип подписчика и, следовательно, тип сообщения, который он содержит) и использовать простое лямбда-выражение, которое я упомянул в первом примере кода, но оно сделает весь код менее «полиморфным», я думаю:
class SubscriberManager {
public void subscribe(EventSubscriber<? extends Event> subscriber) {
}
public void subscribe(MyEventSubscriber subscriber) {
}
}