JavaRush/Java блог/Java Developer/Вопрос-ответ: можно ли в final-классе определить абстракт...

Вопрос-ответ: можно ли в final-классе определить абстрактные методы?

Статья из группы Java Developer
участников
Этот интересный и важный вопрос задали одному из моих читателей во время телефонного собеседования на должность Java-разработчика. Хотя он и знал, что сделать абстрактный класс final-ьным в языке Java нельзя, его смутила формулировка вопроса. Ответ прост: нет, в final-классе не может быть абстрактных методов. Почему? А потому, что как только вы объявляете абстрактный метод в классе языка Java, этот класс автоматически становится абстрактным, а сделать абстрактный класс final’ьным в языке Java нельзя. Значит, абстрактных методов в final-классе Java быть не может.
Вопрос-ответ: можно ли в final-классе определить абстрактные методы? - 1
Многие Java-разработчики путаются при ответе на этот вопрос из-за формулировки. Даже если человек, которому задали вопрос, знаком с общей концепцией, он может не сообразить, что класс, после объявления в нём абстрактного метода становится абстрактным, а сделать абстрактный класс final в языке Java нельзя. Этот момент отделяет данный вопрос от более распространённого и часто задаваемого вопроса: можно ли в Java объявить класс абстрактным и финальным одновременно? Рассмотрим один пример кода, чтобы продемонстрировать, что в final-классе невозможно объявить абстрактный метод. Пусть в Hello.java у нас есть public final класс под названием Hello, в котором есть абстрактный метод print().
public final class Hello {
  public abstract void print();
}
Наберите этот код в IDE, вы получите следующее сообщение об ошибке, дескать Hello должен быть абстрактным классом, чтобы в нём можно было объявлять абстрактные методы.
Вопрос-ответ: можно ли в final-классе определить абстрактные методы? - 2
Вопрос-ответ: можно ли в final-классе определить абстрактные методы? - 3
То же самое произойдет, если вы введете этот код в блокноте и скомпилируете его при помощи утилиты javac из командной строки. Согласно спецификациям Java, как только вы объявляете внутри класса абстрактный метод, этот класс становится абстрактным классом, а раз сделать абстрактный класс final в Java нельзя, компилятор сгенерирует ошибку. Это справедливо как для классов верхнего уровня, так и вложенных классов в языке Java. Даже если объявить абстрактный метод во вложенном final-классе, ошибка будет та же самая. Еще один вытекающий отсюда вопрос: могут ли у абстрактного класса в языке Java быть статические методы? Ответ: да, могут, никакой проблемы с объявлением статического метода в абстрактном классе нет, поскольку для использования статического метода не нужно создавать экземпляр класса, их можно вызывать просто при помощи имени класса. Можно модифицировать наш пример, чтобы включить в класс Hello метод main(), являющийся в языке Java статическим, как показано ниже:
public abstract class Hello {
  public abstract void print();
  public static void main(String args[]) {
     // какой-то код
  }
}
Как вы можете видеть, никакой ошибки при компиляции не выдается. Этот код компилируется без проблем, поскольку в Java можно совершенно спокойно объявлять статический метод в абстрактном классе. Краткие выводы В final-классе невозможно объявить абстрактный метод. Потому что как только вы это сделаете, класс автоматически становится абстрактным, согласно спецификациям Java. А поскольку final-класс в Java не может быть абстрактным, это недопустимо, и компилятор запретит вам подобное действие, выдав ошибку. Но объявлять статические методы можно как в final, так и в абстрактных классах, никаких проблем с этим нет.
Комментарии (6)
  • популярные
  • новые
  • старые
Для того, чтобы оставить комментарий Вы должны авторизоваться
Марат Гарипов
Уровень 108
Expert
14 июня 2022, 21:10
Ни в коем случае не спорю, и согласен, с тем, что объявить абстрактные методы в final-классе нельзя - это понятно. Но ведь вопрос в заглавии статьи был: можно ли в final-классе ОПРЕДЕЛИТЬ абстрактные методы?) мне показалось, что подвох именно в этом) Ведь определить не есть объявить. Если бы мне задали такой вопрос, то я бы уточнил, как раз этот момент. Ведь final-класс может быть наследником абстрактного класса с абстрактными методами, которые хочешь-не хочешь придется переОПРЕДЕЛЯТЬ в классе-наследнике - а это как раз наш final-класс)
Андрей
Уровень 48
20 ноября 2022, 14:33
Есть разница между определить и переопределить, в данном случае речь идет про определение. Если бы было наследование - то это переопределение.
Vadim Karavayev
Уровень 31
19 января 2018, 12:38
А если так final public class FinalDemo { abstract class A { public abstract void doIt(); } } файнал класс есть, в нем абстрактный метод есть. public static void main(String[] args) { FinalDemo fd = new FinalDemo(); FinalDemo.A a = fd.new A() { @Override public void doIt() { System.out.println("Hang in there!"); } }; a.doIt(); }
Максим
Уровень 40
Expert
19 января 2018, 19:36
Если вопрос "можно ли в final-классе определить абстрактные методы?" с подвохом, тогда ваш ответ будет верен)
Денис
Уровень 108
Expert
6 апреля 2022, 05:35
"файнал класс есть, в нем абстрактный метод есть." Хорошо, если есть метод и он паблик, то должно быть FinalDemo fd = new FinalDemo(); fd.doIt(); Но компилятор говорит, что не может найти такой метод и предлагает его создать. Следовательно утверждение "файнал класс есть, в нем абстрактный метод есть." - Не верно! Абстрактный класс - это как чертеж. То что ты сделал, так это поместил у себя в квартире чертеж Белого дома и теперь всем говоришь, что у тебя дома есть Овальный кабинет. Так вот, метод doIt() это и есть Овальный кабинет, который на чертеже, который в твоей квартире. Но твоя квартира не содержит Овальный кабинет.
Stas S
Уровень 108
Expert
15 апреля 2022, 09:56
В final классе есть вложенный абстрактный класс, у которого в свою очередь есть абстрактный метод. Вынесите этот метод в наш final класс и все поломается :)