是否可以使用不同的泛型实现接口两次
很遗憾,没有。您无法两次实现同一接口的原因是类型擦除。编译器将处理类型参数,而运行时只是一个EventListener<X>
EventListener
如果没有,我能做的下一个最接近的事情是什么,以实现我在这里想要做的事情?
类型擦除可以对我们有利。一旦你知道这一点,并且在运行时只是原始的,那么编写一个可以处理不同类型的.Bellow 是一种解决方案,它通过简单的委派来通过测试并正确处理这两个事件:EventListener<X>
EventListener<Y>
EventListener
EventListener
Events
IS-A
EventListener
Login
Logout
@SuppressWarnings("rawtypes")
public class Foo implements EventListener {
// Map delegation, but could be anything really
private final Map<Class<? extends Event>, EventListener> listeners;
// Concrete Listener for Login - could be anonymous
private class LoginListener implements EventListener<LoginEvent> {
public void onEvent(LoginEvent event) {
System.out.println("Login");
}
}
// Concrete Listener for Logout - could be anonymous
private class LogoutListener implements EventListener<LogoutEvent> {
public void onEvent(LogoutEvent event) {
System.out.println("Logout");
}
}
public Foo() {
@SuppressWarnings("rawtypes")
Map<Class<? extends Event>, EventListener> temp = new HashMap<>();
// LoginEvents will be routed to LoginListener
temp.put(LoginEvent.class, new LoginListener());
// LogoutEvents will be routed to LoginListener
temp.put(LogoutEvent.class, new LogoutListener());
listeners = Collections.unmodifiableMap(temp);
}
@SuppressWarnings("unchecked")
@Override
public void onEvent(Event event) {
// Maps make it easy to delegate, but again, this could be anything
if (listeners.containsKey(event.getClass())) {
listeners.get(event.getClass()).onEvent(event);
} else {
/* Screams if a unsupported event gets passed
* Comment this line if you want to ignore
* unsupported events
*/
throw new IllegalArgumentException("Event not supported");
}
}
public static void main(String[] args) {
Foo foo = new Foo();
System.out.println(foo instanceof EventListener); // true
foo.onEvent(new LoginEvent()); // Login
foo.onEvent(new LogoutEvent()); // Logout
}
}
禁止显示警告之所以存在,是因为我们正在“滥用”类型擦除,并根据事件具体类型委托给两个不同的事件侦听器。我选择使用 a 和 运行时 Event ,但是还有很多其他可能的实现。您可以使用匿名内部类(如@user949300建议的那样,可以在 Event 类上包含一个鉴别器,以了解如何处理每个事件,依此类推。HashMap
class
getEventType
通过对所有效果使用此代码,您可以创建一个能够处理两种事件的单个效果。解决方法是 100% 独立(无需公开内部 )。EventListener
EventListeners
最后,还有最后一个问题可能会困扰您。在编译时,类型实际上是 。现在,不受您控制的 API 方法可能期望参数化:Foo
EventListener
EventListener
public void addLoginListener(EventListener<LoginEvent> event) { // ...
// OR
public void addLogoutListener(EventListener<LogoutEvent> event) { // ...
同样,在运行时,这两种方法都处理原始 s。因此,通过实现原始接口,编译器将很乐意让您只得到一个类型安全警告(您可以使用以下命令忽略):EventListener
Foo
@SuppressWarnings("unchecked")
eventSource.addLoginListener(foo); // works
虽然所有这些可能看起来令人生畏,但只要对自己重复一遍“编译器试图欺骗我(或拯救我);没有勺子。一旦你挠了几个月的头,试图让Java 1.5之前编写的遗留代码与充满类型参数的现代代码一起使用,类型擦除就成了你的第二天性。<T>