3

我有一个处理程序的通用接口:

public interface EventHandler<T> {

     boolean handleEvent(T message);
}

你可以实现这个接口和过程T message。您必须将实现的实例传递给EventDispatcher实例。该类在内部存储EventHandler各种类型的多个实例。

在某个时刻,一个事件被触发,EventDispatcher实例调用相应EventHandler的 'shandleEvent()方法并传递一个与 .s 相同类型的消息EventHandler。问题是我不知道哪个是确切的类型,但我确信T message我传递给EventHandler实例具有相同的“T”。

我进行此调用的方式使用原始类型并且有效:

EventHandler handler = getHandler();
Object message = getMessage();
handler.handleEvent(message);

,但我收到警告“未经检查地调用 'handleEvent(T)' 作为原始类型 'EventHandler' 的成员”。

是否可以使用泛型来避免警告?

我想到的一种可能的解决方案是制作一个通用的包装方法:

private <T> boolean handleEventGeneric(EventHandler<T> handler, T message) {
    return handler.handleEvent(message);
}

并使用它:

EventHandler handler = getHandler();
Object message = getMessage();
handleEventGeneric(action.eventHandler, message);

但我不喜欢我必须制作一个包装方法的事实。有没有更优雅的解决方案?

4

2 回答 2

1

无法删除此警告(或至少不能没有@SuppressWarning)。摆脱它的唯一方法是做两件事:

  1. 使你的代码类型证明:所以基本上如果调用代码不使用原始类型,你是类型安全的,或者调用代码使用的是原始类型,如果代码最终不是类型安全的,那是错误的
  2. @SuppressWarning("unchecked")在您的代码上添加。

警告在那里,以便您可以轻松地确定代码中类型安全方面的弱点。如果您正确使用注释,那么您的代码是安全的,并且您肯定不会感到不愉快ClassCastException,除非您愿意@SuppressWarning("unchecked")在您实际上并不完全确定该类型是否安全的地方添加一个。

请参阅一些演示代码来说明我的观点:

import java.util.HashMap;
import java.util.Map;

public class TestGenerics {

    private Map<Class<?>, EventHandler<?>> handlers = new HashMap<Class<?>, TestGenerics.EventHandler<?>>();

    public interface EventHandler<T> {

        boolean handleEvent(T message);
    }

    // Here you force the invoker to provide the correct type of event handler
    // with the given type of klass
    // If he wants to make this fail, then he will have to use rawtype
    public <T> void registerHandler(Class<T> klass, EventHandler<T> handler) {
        handlers.put(klass, handler);
    }

    public <T> void handle(T message) {
        @SuppressWarnings("unchecked") // Here you can add this annotation since you are forcing any invoker to provide a correct EventHandler
        EventHandler<T> handler = (EventHandler<T>) handlers.get(message.getClass());
        if (handler != null) {
            handler.handleEvent(message);
        }
    }

    public static void main(String[] args) {
        TestGenerics test = new TestGenerics();
        test.registerHandler(Long.class, new EventHandler<Long>() {
            @Override
            public boolean handleEvent(Long message) {
                System.out.println("Received a long " + message);
                return true;
            }
        });
        // Here I use raw type but this also means that I created a weak spot in
        // terms of type safety
        EventHandler handler2 = new EventHandler<String>() {
            @Override
            public boolean handleEvent(String message) {
                System.out.println("THis will never print " + message);
                return false;
            }
        };
        test.registerHandler(Integer.class, handler2); // This is where the
                                                        // problem comes from
        test.handle(3L); // OK
        test.handle(1); // ClassCastException

    }

}
于 2015-06-29T21:51:43.947 回答
-1

你可以这样做:

EventHandler<Object> handler = getHandler();
Object message = getMessage();
handler.handleEvent(message);

它不安全,但不比你现在拥有的安全。

于 2015-06-29T21:15:15.297 回答