2016-05-19 9 views
2

У меня возникли трудности с использованием дженериков с константами enum. Я получаю предупреждение компилятора:Предупреждения компилятора с константами перечисления

Неконтролируемый вызова на «ручке (M)» в качестве члена сырого типа «Test.MessageHandler»

на последней строке ниже фрагменте кода.

Любые подсказки о том, как удалить это предупреждение, были бы высоко оценены.

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

Одним из ограничений Java перечислений является то, что вы не можете иметь за значение общего типы. Он не установлен, потому что у вас есть сырой «MessageHandler» - вы могли бы также написать «HANDLERS.get (MessageNumber.LOGOUT)» в предыдущей строке. –

ответ

1

Вы объявили loginHandlerкак сырьевой типа - т.е. нетипизированным:

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

Вместо этого введите переменную для входа в систему, и добавить ролях:

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

You но я все равно получу предупреждение, но на другой строке.

+0

Не работал бы с 'LoginMessage', по крайней мере, без неконтролируемого приведения - вам также нужно было бы сделать« HANDLERS »не сырым, и для этого нужно было бы использовать« MessageHandler »в качестве типа значения. –

+0

@ Энди, да, я набрал это. Обратите внимание, что карта не должна быть не сырой - для решения этой проблемы есть несколько дженериков кунг-фу. См. Update – Bohemian

+0

@ruakh oops ... Я думал о вложенных дженериках. Ты прав. ПОЦЕЛУЙ. – Bohemian

0

Очевидная часть заключается в том, что вы получаете предупреждение, потому что вы не указали параметр типа для MessageHandler в HANDLERS карте.

Но если вы попробуете указать его, вы получите Map<MessageNumber, MessageHandler<? extends Message>>, а затем вы не сможете позвонить handle(), не делая непроверенный актерский состав.

Что все это говорит вам, что Java не может проверить правильность вашего типа отливать статически.

Что вы можете сделать, это выполнить проверку во время выполнения. Если вы хотите проверить, бросание самостоятельно, а не позволяя код, возможно, вызвать ClassCastException, вы могли бы сделать что-то вроде этого:

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);} 
} 
Смежные вопросы