JavaRush/Java блог/Java Developer/10 вопросов по абстрактным классам и интерфейсам с собесе...

10 вопросов по абстрактным классам и интерфейсам с собеседований по Java

Статья из группы Java Developer
участников
Абстрактные классы и интерфейсы очень популярны во всех объектно-ориентированных языках программирования. И практически на каждом собеседовании по Java попадается хотя бы один вопрос на эту тему. Интерфейсы упоминаются чаще, из-за их популярности среди проектировщиков ПО, но время от времени встречаются и вопросы по абстрактным классам. Последние чаще задают претендентам на должность джуниор-разработчиков, скажем, с не более чем двухлетним опытом разработки на Java, в то время как вопросы по интерфейсам чаще всего встречаются при собеседовании тех, чей опыт уже перевалил за четыре года. В основном, их задают вместе с другими вопросами по паттернам проектирования Java, например, по паттернам Decorator (Декоратор) или Factory (Фабрика). 10 вопросов по абстрактным классам и интерфейсам с собеседований по Java - 1В этой статье мы рассмотрим частые вопросы по абстрактным классам и интерфейсам, которые задавались на собеседованиях по Java разного уровня. Большинство из них не должно представлять сложности даже для начинающего Java-программиста. В основном это вопросы на чистое знание, но некоторые из них, например, о различиях между абстрактными классами и интерфейсами в Java или о том, когда лучше предпочесть абстрактный класс интерфейсу, могут оказаться достаточно непростыми. Предлагаем вам десяток интересных вопросов по теме.
Если вам когда-либо задавали на собеседовании или приходилось задавать какой-либо стоящий внимания вопрос об абстрактных классах и интерфейсах, но его в данном списке нет, делитесь им в комментариях.

1. Могут ли в языке Java у абстрактного класса быть конструкторы?

Да, в абстрактном классе в Java можно объявить и определить конструкторы. Поскольку создавать экземпляры абстрактных классов нельзя, вызвать такой конструктор можно только при формировании цепочки конструкторов, то есть при создании экземпляра конкретного класса-реализации. Но представьте, что интервьюер задаст затем вопрос: а какой смысл в конструкторе, если создать экземпляр абстрактного класса все равно нельзя? Дело в том, что его всё равно можно использовать для задания начальных значений общих переменных, объявленных в абстрактном классе и используемых различными реализациями. Даже если вы не объявили никакого конструктора, компилятор добавит в абстрактный класс конструктор по умолчанию без аргументов. Без него ваш подкласс не скомпилируется, поскольку первый оператор в любом конструкторе представляет собой неявный вызов super() – конструктора суперкласса по умолчанию в языке Java.

2. Могут ли абстрактные классы в языке Java реализовывать интерфейсы? Должны ли они реализовывать все методы?

Да, абстрактные классы могут реализовывать интерфейсы с помощью ключевого слова implements. Поскольку они абстрактные, то не обязаны реализовывать все методы. Наличие абстрактного базового класса и интерфейса для объявления типа является рекомендуемой практикой. Пример — интерфейс java.util.List и соответствующий абстрактный класс java.util.AbstractList. Поскольку AbstractList реализует все общие методы, то конкретные реализации (например, LinkedList и ArrayList) не должны реализовать все методы, как в случае, если бы они реализовали интерфейс List напрямую. Это решение сочетает преимущество использования интерфейса для объявления типа и гибкость абстрактного класса для реализации всего общего поведения в одном месте. В книге Джошуа Блоха «Java. Эффективное программирование» есть отличная глава на тему использования интерфейсов и абстрактных классов в Java, для лучшего понимания имеет смысл её изучить.

3. Может ли абстрактный класс быть final?

Нет, не может. Ключевое слово final означает, что класс на вершине иерархии, и у него не может быть наследников. А абстрактный класс без наследников — это сферический конь в вакууме, так как нельзя создать экземпляр abstract class. Таким образом, если класс одновременно abstract и final, то у него нет наследников и нельзя создать его экземпляр. Компилятор Java выдаст ошибку, если сделать класс одновременно abstract и final.

4. Могут ли у абстрактного класса в языке Java быть статические методы?

Да, абстрактные классы могут объявлять и определять статические методы. Только необходимо следовать общим принципам создания статических методов в Java, поскольку они нежелательны при объектно-ориентированном проектировании, ведь переопределение статических методов в Java невозможно. Статические методы в абстрактном классе – явление очень редкое, но, если на это есть уважительные причины, вам ничего не помешает их использовать.

5. Можно ли создать экземпляр абстрактного класса?

Нет, этого делать нельзя. Суть абстрактного класса заключается в том, что он не завершён, и его нужно завершить в классах-наследниках. То есть этот класс не готов к использованию. В нём, например, может отсутствовать реализация каких-то методов. Раз класс не готов к использованию, то нельзя создавать его объект. А вот экземпляры наследников абстрактного класса создавать можно. Компилятор Java выдаст ошибку, если программа попытается создать экземпляр абстрактного класса.

6. Обязательно ли в абстрактном классе должны быть абстрактные методы?

Нет, в абстрактном классе может не быть ни одного абстрактного метода. Сделать класс абстрактным в языке Java можно просто путем использования ключевого слова abstract при объявлении. Компилятор обеспечит выполнение всех структурных ограничений, например, запрета на создание экземпляров этого класса. Кстати, вопрос о том, должны ли быть абстрактные методы в абстрактном классе или интерфейсе – спорный. Мне представляется, что в абстрактном классе должны быть абстрактные методы, поскольку это первое, о чем думает программист, видя абстрактный класс. Это хорошо согласуется с принципом минимизации неожиданностей.

7. Каковы различия между абстрактным классом и интерфейсом в Java?

Это важнейший и один из самых классических вопросов на собеседованиях по языку Java. Я не могу сосчитать, сколько раз встречал этот вопрос на собеседованиях по Java для всех уровней. Интересным этот вопрос делает, в частности, возможность для соискателя представить пример. Отвечать на вопросы по основам объектно-ориентированного программирования, например, рассказать об абстракции, инкапсуляции, полиморфизме и наследовании, легко, но, когда дело доходит до подобных тонких нюансов, претенденты на должность очень часто теряются и говорят, что первое приходит в голову. Ответ на этот вопрос тянет на отдельную статью (особенно после изменений в Java 8), тем не менее, если кратко:
  • Интерфейс описывает только поведение (методы) объекта, а вот состояний (полей) у него нет (кроме public static final), в то время как у абстрактного класса они могут быть.

  • Абстрактный класс наследуется (extends), а интерфейс — реализуется (implements). Мы можем наследовать только один класс, а реализовать интерфейсов — сколько угодно. Интерфейс может наследовать (extends) другой интерфейс/интерфейсы.

  • Абстрактные классы используются, когда есть отношение "is-a", то есть класс-наследник расширяет базовый абстрактный класс, а интерфейсы могут быть реализованы разными классами, вовсе не связанными друг с другом.

8. Когда имеет смысл предпочесть абстрактный класс интерфейсу и наоборот?

Это продолжение предыдущих вопросов по абстрактным классам и интерфейсам. Если вы знаете, каковы их синтаксические различия, то ответ на этот вопрос не доставит вам проблем, так как именно они служат определяющим фактором принятия решения. Поскольку в опубликованный интерфейс практически невозможно добавить новый метод, в случае потенциальной необходимости доработки лучше использовать абстрактный класс. Развивать абстрактные классы в Java проще, чем интерфейсы. Аналогично, если в интерфейсе слишком много методов и реализация их всех становится настоящей головной болью, лучше создать абстрактный класс для реализации по умолчанию. Этому паттерну следуют и в пакете коллекций Java, абстрактный класс AbstractList обеспечивает реализацию по умолчанию для интерфейса List. Используйте абстрактные классы, если:
  • Вы хотите поделиться кодом между несколькими тесно связанными классами.

  • Вы ожидаете, что классы, которые расширяют ваш абстрактный класс, имеют много общих методов или полей, или требуют других модификаторов доступа, кроме public (например, protected и private).

  • Вы хотите объявить нестатические или не-final поля. Это позволяет вам определять методы, которые могут получить доступ и изменить состояние объекта, которому они принадлежат.
Используйте интерфейсы, если:
  • Вы ожидаете, что несвязанные классы будут реализовывать ваш интерфейс. Например, интерфейсы Comparable и Cloneable реализуются многими несвязанными классами.

  • Вы хотите определить поведение конкретного типа данных, но вам не важно, кто его реализует.

  • Вы хотите использовать множественное наследование типа.

9. Что такое абстрактный метод в языке Java?

Абстрактный метод – это метод без тела. Вы просто объявляете метод, не определяя его, с использованием ключевого слова abstract в объявлении метода. Все объявленные внутри интерфейса в языке Java методы – по умолчанию абстрактные. Вот пример абстрактного метода в языке Java:
public void abstract printVersion();
Теперь, для реализации этого метода необходимо расширить абстрактный класс и этот метод переопределить.

10. Может ли абстрактный класс в Java содержать метод main?

Да, абстрактный класс в Java может содержать метод main, ведь это просто еще один статический метод, и абстрактный класс можно выполнять при помощи метода main, если не создавать его экземпляров. Вот и всё, что я хотел рассказать. И помните: абстрактные классы и интерфейсы – ключевые проектные решения в процессе объектно-ориентированного анализа и проектирования, и применять их следует с должной осмотрительностью, конечно, если вы хотите создать гибкую систему.
Комментарии (87)
  • популярные
  • новые
  • старые
Для того, чтобы оставить комментарий Вы должны авторизоваться
Максим Li Java Developer
12 ноября 2023, 22:15
Хорошая статья!
Abubakr05
Уровень 33
18 июля 2022, 10:41
Первый ответ смутил меня. Я создал конструктор и в методе маи объявил его, но идеа подчеркнула его. А в ответе говорится, что можно создать свой конструктор
Anonymous #2436575 Android Developer в AllPets
15 августа 2022, 09:32
Конструктор создать можно, объекты создавать нельзя.
Kirill Akshentsev
Уровень 30
Expert
5 января 2023, 16:07
Конструктор нужен для инициализации полей. Например, у абстрактного класса Car есть поле yearOfManufacture и model - эти поля будут у машины любой категории (Sedan, Truck и тп) -> каждому классу эти поля нет смысла писать. В итоге ты будешь пользовать не конструктором new Car(2014, Tesla M), а методом super(2014, Tesla M ) в конструкторе твоего неабстрактного класса
Anonymous #2575330
Уровень 28
26 декабря 2021, 16:58
abstract после возвращаемого типа не пишется.
KIRUSHIK
Уровень 17
15 ноября 2021, 00:10
к 7-му пункту я бы еще добавил тот факт, что все методы в интерфейсах (кроме default) имеют модификатор доступа public. В то время как, у классов могут быть public, protected, default, private. И вот хорошая статья на эту тему. https://javarush.com/groups/posts/1985-raznica-mezhdu-abstraktnihmi-klassami-i-interfeysami
Anton
Уровень 37
24 мая 2022, 10:57
И еще. С 9й версии Java можно использовать private методы в интерфейсах.
Sergey Kornilov
Уровень 39
25 октября 2021, 08:56
Приз за статью - в студию !
Dina Goncharova
Уровень 39
1 сентября 2021, 20:35
Это было интересно :)
Rostik
Уровень 36
23 марта 2022, 11:26
For real?🙂
Dina Goncharova
Уровень 39
30 марта 2022, 09:40
Oh course ;)
K.
Уровень 39
10 июля 2021, 12:40
Кажется, эта фраза "Аналогично, если в интерфейсе слишком много методов и реализация их всех становится настоящей головной болью, лучше создать абстрактный класс для реализации по умолчанию." устарела, ведь в интерфейсах можно прописывать дефолтные методы
RoMANzhula
Уровень 32
Expert
14 июня 2021, 18:22
Хотелось бы услышать мнение экспертов. Правильно ли я понял данную информацию: Интерфейс - это сборник методов (метода), имеет возможность "цепочкой" пополняться дополнительными методами (множественное наследование) - т.е. это большой МЕТОД состоящий из малых методов. Абстрактный класс - это класс, который может состоять из полей (поля) и методов (от простого метода/методов, до глобального интерфейса). Ассоциация сложилась такая: абстрактный класс - это целое предложение с подлежащим и сказуемым, а вот интерфейс - это только сказуемое в предложении (и оно может интерпретировать до бесконечности). Вопрос - зачем сравнивать класс и метод?
Ruslan
Уровень 19
29 апреля 2021, 12:11
На тех. собеседовании на позицию Java Junior был вопрос по интерфейсу, кому интересно, пример
// Add code to the body of the sayHello() method that calls the printHello() method(extend the code of the B class if necessary)
interface A {

    static void printHello(){
        System.out.println("Hello");
    }
}
class B implements A{
    void sayHello(){

    }
}
hidden #2147043
Уровень 17
26 июня 2021, 18:40
в интерфейс A реализованный метод printHello() нужно определить как default, в методе sayHello() пишем: printHello(). Правильно ответил?
Гэндальф Серый Маг
21 сентября 2021, 09:37
Он же статический, просто вызываем через точку непосредственно у интерфейса. Вопрос, путающий своей простотой.
zotov_l88
Уровень 1
12 января 2022, 14:03
Можно также добавить, что метод класса А не должен по определению быть static, private или final, т.к. нарушается принцип полиморфизма
Anton
Уровень 37
24 мая 2022, 11:05
static методы можно использовать в интерфейсах с 8й версии Java. private методы можно использовать в интерфейсах с 9й версии Java. Не могут быть наследованы классами, реализующие этот интерфейс. История эволюции интерфейсов в Java
Arnold Layne Oracle Developer в Custis
29 марта 2021, 19:54
У меня на собесе спрашивали про наследование интерфейсов, и для чего оно может пригодиться. Думаю, можно осветить здесь этот вопрос. И еще, похоже, Элеонора опять забыла, какого она пола: "Вот и всё, что я хотел рассказать" ..)