当类型未知时,如何避免使用原始类型和使用泛型?

时间:2015-06-28 11:20:01

标签: java events generics raw-types

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

public interface EventHandler<T> {

     boolean handleEvent(T message);
}

您可以实施此界面并处理T message。您必须将实现的实例传递给EventDispatcher实例。该类在内部存储多个不同类型的EventHandler个实例。

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

我打电话的方式使用原始类型和作品:

EventHandler

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

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

我想到的一个可能的解决方案是创建一个通用的包装器方法:

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

并使用它:

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

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

2 个答案:

答案 0 :(得分:1)

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

  1. 使您的代码类型证明:所以基本上如果调用代码不使用原始类型,您是类型安全的或调用代码使用rawtypes并且如果代码最终不是类型安全则它是错误的
  2. 在代码中添加@SuppressWarning("unchecked")
  3. 警告就在那里,以便您可以在代码中轻松识别出类型安全方面的弱点。如果您正确使用注释,那么您的代码是安全的,并且您确定没有得到任何令人不快的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
    
        }
    
    }
    

答案 1 :(得分:-1)

你可以这样做:

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

这不安全,但不比现在安全。