Подтвердить что ты не робот

Переопределение метода с помощью общих параметров в 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?

4b9b3361

Ответ 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, и т.д. Он намного чище, чем альтернатива, которая получала бы/отправляла необработанный список и затем вынуждала бы его требовать тип, приводящий к потенциальным исключениям исключения в режиме исполнения.