Если посмотреть на SchedulingTask
, это класс, который расширяет родительский класс SerialTask
, а также объявляет, что он реализует интерфейс ISchedulingTask
. Реализация интерфейса означает, что SchedulingTask
обещает реализовать интерфейс, чтобы любой, кто использует этот класс, мог знать, что в нем есть метод run()
. Обратите внимание, что интерфейс на самом деле не реализует функцию run
, он просто объявляет, что он существует в указанной сигнатуре c (не принимает параметров и ничего не возвращает).
Поскольку SerialTask
реализует run
publi c, то все, что расширяет ее, также будет иметь эту реализацию. Фактически, в приведенном вами коде это единственное место, где фактически реализована функция run
.
Обратите внимание, что SchedulingTask
не реализует функцию run
, хотя говорит, что реализует интерфейс. Обычно это была бы ошибка времени компиляции, поскольку класс не реализует требуемые функции интерфейса, но поскольку у его родителя они есть, все в порядке, и эта функция используется в rutime.
Лучше способ упорядочить вещи - заставить класс SerialTask
реализовывать интерфейс ISchedulingTask
, поскольку именно там он действительно реализован. Поскольку SchedulingTask
расширяет его, он также автоматически реализует интерфейс, поэтому на самом деле ничего не меняется с точки зрения того, как пользователи SchedulingTask
видят его функциональность, но более ясно, откуда взялась функция run
.
Обратите внимание, что любой подкласс, расширяющий родительский элемент или реализующий интерфейс, может реализовать свою собственную версию функции run
и что среда выполнения будет использовать первую, с которой столкнется.
Функция run
ищется в следующем порядке:
- SchedulingTask.run -> явно не существует в классе
- parent: SerialTask. run -> существует, поэтому используется