2016-05-19 4 views
2

enumの定数でジェネリックを使用するのが難しいです。以下のスニペットの最後の行に「Test.MessageHandler」列挙定数を使用したコンパイラの警告

生タイプのメンバーとして「ハンドル(M)」に

未確認コール:私は、コンパイラの警告を取得しています。

この警告を削除する方法についてのヒントは、高く評価されます。

public class Test { 
    private enum MessageNumber { 
     LOGIN, 
     LOGOUT 
    } 

    private interface Message {} 
    private static class LoginMessage implements Message {} 
    private static class LogoutMessage implements Message {} 

    private interface MessageHandler<M extends Message> { 
     void handle(M msg); 
    } 

    private static class LoginMessageHandler implements MessageHandler<LoginMessage> { 
     public void handle(LoginMessage msg) {System.out.println(msg);} 
    } 
    private static class LogoutMessageHandler implements MessageHandler<LogoutMessage> { 
     public void handle(LogoutMessage msg) {System.out.println(msg);} 
    } 

    private static final Map<MessageNumber, MessageHandler> HANDLERS = new ConcurrentHashMap<MessageNumber, MessageHandler>() {{ 
     put(MessageNumber.LOGIN, new LoginMessageHandler()); 
     put(MessageNumber.LOGOUT, new LogoutMessageHandler()); 
    }}; 

    public static void main(String[] args) { 
     MessageHandler loginHandler = HANDLERS.get(MessageNumber.LOGIN); 
     loginHandler.handle(new LoginMessage()); //Compiler warning: Unchecked call to 'handle(M)' as a member of raw type 'Test.MessageHandler' 
    } 
} 
+3

一つは、あなたが持つことができないということですごとの値は、一般的なタイプ。これは未処理の 'MessageHandler'を持っているためチェックされません。前の行に' HANDLERS.get(MessageNumber.LOGOUT) 'と同じように書くことができます。 –

答えて

1

あなたは型としてloginHandlerを宣言した - すなわち型なし:

MessageHandler loginHandler = HANDLERS.get(MessageNumber.LOGIN); 

代わりに、ログインのための変数を入力して、キャストを追加します。

MessageHandler<LoginMessage> loginHandler = 
    (MessageHandler<LoginMessage>)HANDLERS.get(MessageNumber.LOGIN); 

あなたはしかし、まだ別の行で、警告が表示されます。

+0

少なくともチェックされていないキャストがなくても、 'LoginMessage'ではうまくいかないでしょう。' HANDLERS'も非rawにする必要があります。値型として 'MessageHandler 'を使う必要があります。 –

+0

@Andyええ - 私はそれを入力しています。地図は非生のものである必要はありません - それに対処するためには少しの一般的なkung fuがあります。 update – Bohemian

+0

@ruach oopsを参照してください...私は入れ子のジェネリックを考えていました。あなたが正しい。キッス。 – Bohemian

0

MessageHandlerの型パラメータをHANDLERSマップに指定していないため、警告が表示されることが明らかです。

しかし、指定しようとすると、Map<MessageNumber, MessageHandler<? extends Message>>になります。チェックされていないキャストを行わずにhandle()に電話をかけることはできません。このすべてがあなたを語っている何

Javaは静的あなたのタイプキャストの正しさを確認することができないということです。

実行可能なことは、実行時にチェックを実行することです。あなたはおそらくClassCastExceptionをトリガーするコードを許すのではなく、キャストを自分で確認したい場合は、このような何かを行うことができます。Javaの列挙型の制限の

private interface MessageHandler { 
    void handle(Message msg); 
} 

private static class TypedMessageHandler<M extends Message> { 
    private final Class<M> clazz; 

    public TypedMessageHandler(M clazz) { 
     this.clazz = clazz; 
    } 

    public void handle(Message msg) { 
     if (msg == null || clazz.isAssignableFrom(msg.getClass()) { 
      handleInternal((M) msg); 
     } else { 
      // your error logic 
     } 
    } 

    abstract protected void handleInternal(M msg); 
} 

private static class LoginMessageHandler extends TypedMessageHandler<LoginMessage> { 

    public LoginMessageHandler() { 
     super(LoginMessage.class); 
    } 

    protected void handleInternal(LoginMessage msg) {System.out.println(msg);} 
} 

private static class LogoutMessageHandler extends TypedMessageHandler<LogoutMessage> { 

    public LogoutMessageHandler() { 
     super(LogoutMessage.class); 
    } 

    protected void handleInternal(LogoutMessage msg) {System.out.println(msg);} 
} 
関連する問題