2015-06-28 52 views
3

我有一個處理一個通用接口:如何避免使用原始類型並在類型未知時使用泛型?

public interface EventHandler<T> { 

    boolean handleEvent(T message); 
} 

您可以實現此界面和流程T message。您必須將實施的實例傳遞給EventDispatcher實例。該類在內部存儲多個各種類型的EventHandler實例。

在某些點的事件被觸發並且EventDispatcher實例調用相應EventHandlerhandleEvent()方法和傳遞的消息是相同的類型EventHandler。問題是我不知道哪一個是確切類型,但我確信我傳遞給EventHandler實例的T message具有相同的「T」。

我做這個調用使用原始類型和工作方式:

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

,但我得到警告「以‘爲handleEvent(T)’爲原料型‘事件處理程序’的成員未選中呼叫」。

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

我已經想到了一種可能的解決方案是一個通用的包裝方法:

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

,並使用它:

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

但我不喜歡的事實,我必須做出一個包裝方法。有沒有更優雅的解決方案?

+3

這第二代碼片段仍然使用原始類型:

見說明我的觀點的一些演示代碼。 –

+1

但這聽起來像是一個無法解決的問題;您正嘗試使用基於僅在運行時可用的信息的編譯時類型安全性。 –

+0

最後一個代碼示例不使用'handler'變量。有錯誤嗎?另請提供'getHandler()'和'getMessage()'方法的簽名。 –

回答

1

不可能刪除此警告(或者至少不是沒有@SuppressWarning)。

  1. 使你的代碼類型證明:所以基本上如果調用代碼不使用原始類型,你是類型安全或調用代碼使用rawtypes和唯一的辦法是做兩件事情擺脫它如果代碼最終沒有安全類型,這是錯誤的
  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 

    } 

} 
-1

你可以這樣做:

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

這不是安全的,但並不比你現在有什麼不太安全。

+0

其實這是非常錯誤的。這正是你不應該做的。將這個片段替換爲你更喜歡'List list = getList(); list.add(「MyString」);'你在哪裏有'public List getList(){返回一些列表};'因爲你正在向整數列表中添加一個字符串,所以你最終會遇到堆污染。 –

相關問題