Переопределение метода с помощью общих параметров в Java?
У меня есть абстрактный класс Monitor.java, который подклассифицирован классом EmailMonitor.java.
Метод:
public abstract List<? extends MonitorAccount> performMonitor(List<? extends MonitorAccount> accounts)
определяется в Monitor.java и должен быть переопределен в EmailMonitor.java.
В настоящее время метод переопределяется в EmailMonitor.java следующим образом:
@Override
public List<EmailAccount> performMonitor(List<EmailAccount> emailAccounts) {
//...unrelated logic
return emailAccounts;
}
Однако это приводит к ошибке времени компиляции:
Name clash: The method performMonitor(List<EmailAccount>) of type EmailMonitor has the same erasure as performMonitor(Lis<? extends MonitorAccount> emailAccounts) of type Monitor but does not override it
EmailAccount
является подклассом MonitorAccount
, поэтому (по моему мнению, по крайней мере), переопределяя его таким образом, имеет смысл. Увидев, что компилятор не удовлетворен моей логикой, как это сделать, я должен правильно это сделать, сохраняя мои проверки времени компиляции, чтобы убедиться, что все вызовы EmailMonitor.performMonitor()
получают списки EmailAccount
, а не какой-либо другой тип MonitorAccount
?
Ответы
Ответ 1
Нет, это не отменяет его должным образом. Переопределение означает, что вы должны иметь возможность справиться с любым допустимым вводом базового класса. Подумайте, что произойдет, если клиент сделает это:
Monitor x = new EmailMonitor();
List<NonEmailAccount> nonEmailAccounts = ...;
x.performMonitor(nonEmailAccounts);
Там ничего нет, что должно дать ошибку времени компиляции, учитывая ваше описание, но это явно неправильно.
Мне кажется, что Monitor
должен быть общим в типе учетной записи, которую он может контролировать, поэтому ваш EmailMonitor
должен расширять Monitor<EmailAccount>
. Итак:
public abtract class Monitor<T extends MonitorAccount>
{
...
public abstract List<? extends T> performMonitor(
List<? extends T> accounts);
}
public class EmailMonitor extends Monitor<EmailAccount>
{
@Override
public abstract List<? extends EmailAccount> performMonitor(
List<? extends EmailAccount> accounts)
{
// Code goes here
}
}
Возможно, вам стоит подумать о дженериках в вызове performMonitor
, хотя, что означает возвращаемое значение, означающее?
Ответ 2
Вот мое собственное решение. Я подозреваю, что это то же самое, что Джон Скит пытался получить... без опечатки (см. Мой комментарий в ответ на его ответ).
класс Monitor.java:
public abstract class Monitor <T extends MonitorAccount> {
...
public abstract List<T> performMonitor(List<T> accounts);
..
}
EmailMonitor.java
public class EmailMonitor extends Monitor<EmailAccount> {
...
public List<EmailAccount> performMonitor(List<EmailAccount> emailAccounts) {
..//logic...logic...logic
return emailAccounts;
}
...
}
В этой конфигурации EmailMonitor.performMonitor() всегда будет проверять во время компиляции, что он получает список EmailAccount, а не любой из моих других типов FTPAccount, DBAccount, и т.д. Он намного чище, чем альтернатива, которая получала бы/отправляла необработанный список и затем вынуждала бы его требовать тип, приводящий к потенциальным исключениям исключения в режиме исполнения.