2015-06-18 1 views
7

Я получаю ошибку ниже:Почему этот метод вызывает отказ? (Обобщения и групповые символы)

'call(ContainsMonitor)' cannot invoke 'call(? extends webscout.Monitor)' in 'WebScoutCallable' 

Monitor.java

WebScoutCallable<? extends Monitor> handler; 

public setCallable(WebScoutCallable<? extends Monitor> callable) { 
    this.handler = callable; 
} 

WebScoutCallable.java

public interface WebScoutCallable<T extends Monitor> { 
    public void call(T caller); 
} 

ContainsMonitor.java

public class ContainsMonitor extends Monitor { 
    public void handleDocument() { 
      handler.call(this); 
    } 
} 

Я буду свободно признавать, что я новичок в дженериках и по-прежнему новичок в самой Java. Я нахожу сообщение об ошибке запутанным, так как похоже, что он должен работать (объявление метода ожидает монитор или подкласс, я передаю в подкласс). Любая помощь (+ объяснение) будет принята с благодарностью!

Спасибо!

ответ

6

Вы подстановочные знаки в параметре типа вашей handler переменной. Компилятор не знает, что такое точный тип этого параметра, только то, что это либо Monitor, либо подкласс.

Метод call принимает T, что соответствует шаблону. Но нет никакой гарантии, что тип подстановочных знаков - ContainsMonitor. Это может быть Monitor, или это может быть MonitorSubtypeThatDoesntExistYet. Поскольку компилятор не знает фактического типа, он не может пропускать ничего, кроме null, потому что с любым аргументом не null он не может гарантировать безопасность типа.

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

class Monitor<T extends Monitor<T>> 
{ 
    WebScoutCallable<T> handler; 

    public void setCallable(WebScoutCallable<T> callable) { 
     this.handler = callable; 
    } 
} 

Интерфейс WebScoutCallable немного меняется в ответ:

interface WebScoutCallable<T extends Monitor<T>> { 
    public void call(T caller); 
} 

Подкласс питает свое собственное имя в качестве аргумента типа при расширении Monitor.

class ContainsMonitor extends Monitor<ContainsMonitor> { 
    public void handleDocument() { 
      handler.call(this); 
    } 
} 

Теперь T будет известный тип, и ContainsMonitor определяет это быть самим собой, так что теперь законно это передать себя call.

+0

Благодарим за подробный ответ. Я думал, что может быть менее сложное решение, но это имеет смысл! – RNGuy

3

? extends Monitor означает: отдельный подкласс Монитора, но мы не знаем, какой из них. Таким образом, это может быть ContainsMonitor или нет, и handler может принять или не принять ContainsMonitor. Компилятор не может решить и показывает ошибку.

Один из способов решить проблему является использование определенных типов, например:

class Monitor<T extends Monitor<T>> { 
    WebScoutCallable<T> handler; 

    public setCallable(WebScoutCallable<T> callable) { 
    this.handler = callable; 
    } 
} 

class ContainsMonitor extends Monitor<ContainsMonitor> { 
    public void handleDocument() { 
    handler.call(this); 
    } 
} 
+0

Спасибо за быстрый ответ. Хотел бы я отметить два решения, как правильно! – RNGuy

-5

Ваш код не требует никаких дженериков.

public class Monitor { 
    WebScoutCallable handler; 

    public void setCallable(WebScoutCallable callable) { 
     this.handler = callable; 
    } 
} 

public interface WebScoutCallable { 
    public void call(Monitor caller); 
} 

public class ContainsMonitor extends Monitor { 
    public void handleDocument() { 
      handler.call(this); 
    } 
} 
+3

Это не отвечает на вопрос OP –

Смежные вопросы