Cli*_*ote 27 java generics interface
我有以下界面,我想在我的类中多次实现:
public interface EventListener<T extends Event>
{
public void onEvent(T event);
}
Run Code Online (Sandbox Code Playgroud)
现在,我希望能够以下列方式实现此接口:
class Foo implements EventListener<LoginEvent>, EventListener<LogoutEvent>
{
@Override
public void onEvent(LoginEvent event)
{
}
@Override
public void onEvent(LogoutEvent event)
{
}
}
Run Code Online (Sandbox Code Playgroud)
但是,这给了我错误:Duplicate class com.foo.EventListener
在线:
class Foo implements EventListener<LoginEvent>, EventListener<LogoutEvent>
Run Code Online (Sandbox Code Playgroud)
是否可以使用不同的泛型实现两次接口?如果没有,那么我能做到的最接近的事情是如何实现我在这里尝试做的事情?
Ant*_*oly 20
是否可以使用不同的泛型实现两次接口
很不幸的是,不行.您无法两次实现相同接口的原因是因为类型擦除.编译器将处理类型参数,运行时EventListener<X>
只是一个EventListener
如果没有,那么我能做到的最接近的事情是如何实现我在这里尝试做的事情?
类型擦除可以对我们有利.一旦你知道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
}
}
Run Code Online (Sandbox Code Playgroud)
抑制警告是存在的,因为我们"滥用"类型擦除并根据事件具体类型委托给两个不同的事件监听器.我选择使用a HashMap
和运行时事件来做class
,但是还有很多其他可能的实现.您可以使用@ user949300建议的匿名内部类,您可以getEventType
在Event类中包含一个鉴别器,以了解每个事件的作用等等.
通过将此代码用于所有效果,您可以创建一个EventListener
能够处理两种事件的单一事件.解决方法是100%自包含(不需要暴露内部EventListeners
).
最后,最后一个问题可能会让您烦恼.在编译时,Foo
类型实际上是EventListener
.现在,您无法控制的API方法可能需要参数化EventListener
:
public void addLoginListener(EventListener<LoginEvent> event) { // ...
// OR
public void addLogoutListener(EventListener<LogoutEvent> event) { // ...
Run Code Online (Sandbox Code Playgroud)
同样,在运行时,这两种方法都处理原始EventListener
s.因此,通过Foo
实现原始接口,编译器将很乐意让您远离类型安全警告(您可以忽略它@SuppressWarnings("unchecked")
):
eventSource.addLoginListener(foo); // works
Run Code Online (Sandbox Code Playgroud)
虽然所有这些看起来令人生畏,但只要重复一遍"编译器试图欺骗我(或拯救我);没有 勺 <T>
.一旦你试图在Java 1.5使用现代代码充满类型参数的情况下编写遗留代码几个月之后,类型擦除就成了你的第二天性.
use*_*300 11
您需要使用内部或匿名类.例如:
class Foo {
public EventListener<X> asXListener() {
return new EventListener<X>() {
// code here can refer to Foo
};
}
public EventListener<Y> asYListener() {
return new EventListener<Y>() {
// code here can refer to Foo
};
}
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
12045 次 |
最近记录: |