@MustOverride аннотация?
В .NET можно указать атрибут "mustoverride" для метода в определенном суперклассе, чтобы гарантировать, что подклассы переопределяют этот конкретный метод.
Мне было интересно, есть ли у кого-нибудь пользовательская аннотация java, которая может достичь того же эффекта. По сути, я хочу, чтобы подклассы переопределяли метод в суперклассе, который сам имеет некоторую логику, которая должна выполняться. Я не хочу использовать абстрактные методы или интерфейсы, потому что я хочу, чтобы в супер-методе выполнялась какая-то общая функциональность, но более или менее выдает предупреждение/ошибку компилятора, обозначающее, что производные классы должны переопределять данный метод.
Ответы
Ответ 1
Я не совсем понимаю, почему вы не хотите использовать абстрактный модификатор - это предназначено для принудительной реализации подкласса и нужно использовать только для некоторых методов, а не для всех. Или, может быть, вы думаете о "чистых абстрактных" классах на С++?
Но еще одна вещь, о которой многие разработчики Java не знают, заключается в том, что также можно переопределить не абстрактные методы и объявить их абстрактными; как:
public abstract String toString(); // force re-definition
так что даже если java.lang.Object
уже определяет реализацию, вы можете заставить подклассы снова определить ее.
Ответ 2
Игнорируя абстрактные методы, на Java нет такого средства. Возможно, его можно создать аннотацию времени компиляции, чтобы заставить это поведение (и я не уверен, что оно есть), но что оно.
Реальный кикер - это "переопределить метод в суперклассе, который сам имеет некоторую логику, которая должна выполняться". Если вы переопределите метод, метод суперкласса не будет вызываться, если вы его явно не назовете.
В таких ситуациях я обычно делал что-то вроде:
abstract public class Worker implements Runnable {
@Override
public final void run() {
beforeWork();
doWork();
afterWork();
}
protected void beforeWork() { }
protected void afterWork() { }
abstract protected void doWork();
}
чтобы заставить определенную логическую структуру по методу интерфейса. Вы можете использовать это, например, для подсчета вызовов, не беспокоясь о том, вызывает ли пользователь super.run()
и т.д.
Ответ 3
... и если объявление базового класса abstract
не является вариантом, вы всегда можете выкинуть UnsupportedOperationException
class BaseClass {
void mustOverride() {
throw new UnsupportedOperationException("Must implement");
}
}
Но это, конечно, не проверка времени компиляции...
Ответ 4
Я не уверен, какой атрибут вы думаете в .NET.
В VB вы можете применить модификатор MustOverride
к методу, но это эквивалентно тому, чтобы сделать абстрактным метод на Java. Вам не нужен атрибут/аннотация, поскольку концепция встроена в языки. Это больше, чем просто применение метаданных - там также решающее различие заключается в том, что абстрактный метод не включает в себя никакой реализации.
Если вы думаете, что есть такой атрибут, пожалуйста, можете ли вы сказать, какой из них вы имеете в виду?
Ответ 5
В Android появилась новая аннотация, объявленная в Google I/O 2015:
@callSuper
Подробнее здесь:
http://tools.android.com/tech-docs/support-annotations
Ответ 6
Если вам нужно какое-то поведение по умолчанию, но по какой-то причине оно не должно использоваться специализациями, например, реализация логики в не абстрактном классе Adapter для простоты прототипирования, но которая не должна использоваться в производстве, например, вы можете инкапсулировать эту логику и зарегистрировать предупреждение о том, что она используется, без необходимости ее запускать.
Конструктор базового класса может проверить, соответствует ли переменная, содержащая логику, по умолчанию. (написав в очень абстрактных терминах, поскольку я думаю, что он должен работать на любом языке)
Это будет что-то вроде этого (нескомпилированный, непроверенный и неполный) пример Java (до 7):
public interface SomeLogic {
void execute();
}
public class BaseClass {
//...private stuff and the logging framework of your preference...
private static final SomeLogic MUST_OVERRIDE = new SomeLogic() {
public void execute() {
//do some default naive stuff
}
};
protected SomeLogic getLogic() { return MUST_OVERRIDE; }
//the method that probably would be marked as MustOverride if the option existed in the language, maybe with another name as this exists in VB but with the same objective as the abstract keyword in Java
public void executeLogic() {
getLogic().execute();
}
public BaseClass() {
if (getLogic() == MUST_OVERRIDE) {
log.warn("Using default logic for the important SomeLogic.execute method, but it is not intended for production. Please override the getLogic to return a proper implementation ASAP");
}
}
}
public GoodSpecialization extends BaseClass {
public SomeLogic getLogic() {
//returns a proper implementation to do whatever was specified for the execute method
}
//do some other specialized stuff...
}
public BadSpecialization extends BaseClass {
//do lots of specialized stuff but doesn't override getLogic...
}
Некоторые вещи могут быть разными в зависимости от требований и явно проще, особенно для языков с лямбда-выражениями, но основная идея будет одинаковой.
Без встроенного встроенного устройства всегда есть способ его эмулировать, в этом примере вы получите предупреждение о запуске в файле журнала с помощью шаблона с домашним шаблоном, который должен указывать только ваши потребности, если достаточно или более хардкорного манипулирования байт-кодами, разработки плагинов ide или любого другого волшебства.
Ответ 7
Я думал об этом.
Пока я не знаю, как это сделать с ошибкой компиляции, вы можете попробовать написать собственное правило PMD, чтобы поднять красный флаг, если вы забыли переопределить.
Уже существует множество правил PMD, которые напоминают вам о реализации HhashCode, если вы решите переопределить равные. Возможно, что-то можно сделать так.
Я никогда раньше этого не делал, поэтому я не один, чтобы написать учебник, но хорошим местом для начала будет эта ссылка http://techtraits.com/programming/2011/11/05/custom-pmd-rules-using-xpath/ В этом примере он в основном создает небольшое предупреждение, если вы решите использовать подстановочный знак в пакете импорта. Используйте его как отправную точку, чтобы изучить, как PMD может анализировать исходный код, посещать каждого члена иерархии и определять, где вы забыли реализовать определенный метод.
Аннотации также возможны, но вам нужно будет выяснить свой собственный способ реализации навигации по пути к классу. Я считаю, что PMD уже справляется с этим. Кроме того, PMD имеет очень хорошую интеграцию с IDE.
https://pmd.github.io/