Я отразлю другие ответы и скажу, что не существует принудительного компилятора способа заставить производные классы переопределять неабстрактный метод.Весь смысл создания абстрактного метода состоит в том, чтобы определить, что метод с этой сигнатурой должен существовать, но не может быть указан на базовом уровне и, следовательно, должен быть указан на производном уровне.Если есть рабочая, нетривиальная реализация (так как она не пустая и не просто выдает исключение или показывает сообщение) метода на базовом уровне, то это не является строго необходимым для вызоваметод от потребителя производного класса, чтобы преуспеть.Таким образом, компилятору не нужно принудительно переопределять метод, который может довольно успешно работать на базовом или производном уровнях.
В ситуациях, когда вы хотите, чтобы производный класс переопределял вашу рабочую реализацию, должно быть совершенно очевидно, что базовая реализация не делает то, что захотят потребители производного класса;базовый класс либо не имеет достаточной реализации, либо неправильной.В этих случаях вы должны верить, что программист, унаследованный от вашего класса, будет знать, что он делает, и поэтому знает, что метод необходимо переопределить, поскольку он не дает правильного ответа в контексте использования его нового объекта.
Я могу вспомнить одну вещь, которую вы могли бы сделать.Это потребовало бы абстрактной базы с запечатанной (окончательной для Javaheads) реализацией «по умолчанию».Таким образом, существует базовая реализация метода, которую легко использовать, как если бы это был «базовый» класс, но для определения другого класса для нового сценария необходимо вернуться к абстрактному классу, иТаким образом, вынуждены переопределить метод.Этот метод может быть единственной абстрактной вещью в классе, тем самым позволяя вам использовать базовые реализации других методов:
public abstract class BaseClass
{
public abstract void MethodYouMustAlwaysOverride();
public virtual void MethodWithBasicImplementation() { ... }
}
public final class DefaultClass:BaseClass
{
public override void MethodYouMustAlwaysOverride() { ... }
//the base implementation of MethodWithBasicImplementation
//doesn't have to be overridden
}
...
public class DerivedClass:BaseClass
{
//Because DefaultClass is final, we must go back to BaseClass,
//which means we must reimplement the abstract method
public override void MethodYouMustAlwaysOverride() { ... }
//again, we can still use MethodWithBasicImplementation,
//or we can extend/override it
public override void MethodWithBasicImplementation() { ... }
}
Однако у этого есть два недостатка.Во-первых, поскольку у вас нет доступа к реализации DefaultClass посредством наследования, вы не можете расширить реализацию DefaultClass, то есть, чтобы сделать то, что делает DefaultClass, плюс еще немного, вы должны переписать код из DefaultClass, нарушая DRY.Во-вторых, это работает только для одного уровня наследования, потому что вы не можете принудительно переопределить, если разрешаете наследование от DerivedClass.