Топ-5 популярных вопросов на Android собеседовании [2025]

от автора

Топ-5 вопросов на Android интервью

Топ-5 вопросов на Android интервью

Cобеседования в IT — это всегда вызов и Android тут, конечно же, не исключение. Для успешного прохождения интервью в крупные и востребованные компании современный Android-разработик должен держать в голове огромное количетсво областей: от «базы» в виде Computer Science (структуры данных, алгоритмы) и навыков проектирования (архитектура, паттерны, System Design) до знания Java, Kotlin и, разумеется Android SDK. Добавим сюда и популярные фреймворки и библиотеки (которые к тому же устаревают каждые пару лет!) вроде RxJava и Kotlin Coroutines и получается совсем уж, на первый взгляд, неподъемный багаж необходимых знаний… К счастью, многие вопросы пересекаются между компаниями, так что наработав некоторую «базу» из них вы сильно повысите свои шансы на положительный результат и заветный оффер 🙂 Давайте разберем ТОП-5 вопросов, с которыми можно столкнуться в крупных компаниях на российском рынке, поехали!

1. Перечислите принципы, входящие в SOLID.

Вопрос вне времен и трендов: годы идут, а значительная часть интервью не обходится без этой темы. Чаще всего, все ограничивается перечислением и принципов и их коротким описанием, потому кратко давайте разберем их.

Single Responsibility: часто неправильно понимается, как «модуль или класс должны отвечать за что-то одно». Это отчасти верно, но речь идет не только об ответственности класса, но еще и о причинах для его изменения, точнее о группе лиц, которым может потребоваться его изменить: «модуль должен отвечать только за одного актора» (где актор — 1 или более лиц, объединенных группой, например — «бухгалтерия», «отдел кадров»).

Open-Closed: сущности программы должны быть открыты для расширения и закрыты для из изменений. Простое расширение (а не изменение) требований не должно вести к значительным изменениям кода, иначе — это архитектурная ошибка, произошедшая по причине нарушения этого принципа.

Liskov Substitution: тут речь идёт о правильной иерархии наследования. Везде, где мы можем использовать 1 класс (базовый, например), мы должны иметь возможность использовать и его наследников без неожиданного поведения. Мораль — наследники должны писаться разумно и должны дополнять, а не замещать или искажать поведение базового класса.

Interface Segregation:  пожалуй, самый простой и понятный из принципов, где не часто бывают различные интерпретации. Принцип говорит о том, что несколько узко специализированных интерфейсов лучше, чем один большой. Один большой интерфейс может заставить классы, которые его реализуют, имплементировать методы, которые могут быть им и не нужны в конкретных случаях, что приводит к лишней работе или засорению кода пустыми реализациями.

Dependency Inversion: Принцип гласит, что модули верхнего уровня не должны зависеть от модулей нижнего, и те и другие должны зависеть от абстракций И абстракции не должны зависеть от деталей, детали должны зависеть от абстракций. На практике это выглядит так: классы не должны создавать другие классы внутри себя, особенно конкретные реализации. Эти зависимости должны поставляться ИЗВНЕ, то есть инвертироваться.

Будьте готовы к усложнениям и вариациям, например:

  • Какой из данных принципов на ваш взгляд наиболее важный?

  • Какие нарушения принципов SOLID вы можете вспомнить в стандартных классах из Java, Kotlin или Android SDK?

Что почитать:

2. Как работает HashMap? Как происходит разбиение на бакеты? Что такое коллизии? Какую роль играют реализации equals/hashCode методов у добавляемых объектов?

HashMap — излюбленная коллекция у многих собеседующих. Тема эта достаточно обширная, но, к счастью, материалов на этот счёт написано огромное количество:

3. Что такое data классы в Kotlin? Зачем они нужны, чем отличаются от обычных?

Data classes — это по праву одна из наиболее любимых многими фич Котлина! Собеседующие, правда, тоже попадают в эту категорию, потому они очень и очень любят задавать о ней вопросы. Начать знакомство с ними стоит в документации, чтобы понять базовые идеи.

Но стоит быть готовым и к усложнениям:

  • Чем data класс отличается от value класса? (это довольно разные концепты, см. документацию для value класса)

  • Что такое data object? В чем разницу между data class и data object? (см. документацию)

  • Какую информацию из data класса компилятор использует для генерации equals/hashCode/toString? (поля конструктора, переменные вне конструктора не используются)

  • Что будет, если объявить поля конструктора data класса как var, а не val? (ничего криминального, но это нарушает идею data классов — класс перестает быть неизменяемым, наличие сгенерированной функции copy() начинает выглядеть странно и т.д.)

  • Есть ли у data классов какие-то недостатки? Нельзя ли просто все классы объявлять именно как data? (есть, например, они влияют на размер приложения из-за кодогенерации)

4. Какие «основные» компоненты Андроид вы знаете и почему они так называются?

Под “основными” понимаются те компоненты, которые могут являться точкой входа в приложение. Теоретически, приложение может состоять только из одного из таких компонентов, зарегистрированного в AndroidManifest, в этом и заключается их особенность. Согласно документации, всего их 4:

Т.е. да, вы можете создать приложение, в котором нет никакого привычного UI и которое состоит из одного лишь BroadcastReceiver или Service и, возможно, даже выложить его в Google Play.

5. Как создать новую корутину? Перечислите все способы, которые знаете.

Основной способ запуска корутин — это использование т.н. Coroutine Builders:

  • launch: запускает новую корутину и возвращает связанный с ней Job. Этот Job не предоставляет типизированного результата, а просто служит индикатором выполнения + позволяет отменить выполняемую работу. Подходит, когда не нужен или не важен результат выполнения корутины, нужно просто запустить ее и выполнить.

  • async: в отличии от launch возвращает не Job, а Deferred<T>. Это future/promise, который по умолчанию уже находится в запущенном состоянии (это можно контролировать через параметр start). Чтобы дождаться результата выполнения необходимо вызвать await на возвращенном Deferred объекте. Этот билдер удобен, когда необходимо получить результат выполнения работы корутины, а не просто Job из launch.

  • runBlocking: запускает новую корутину и блокирует вызывавший поток до ее завершения. Возвращается не Job или Defferred, а обычный типизированный тип T. Этот способ не является основным, т.к. он сводит преимущества suspending функций на «нет», но он бывает полезен в случаях, когда нужно вызывать корутины из какого-то старого кода, библиотек без поддержки kotlin и/или корутин + иногда используется при написании тестов.

launch, async являются extension функциями над CoroutineScope, т.е. их нельзя вызвать вне контекста корутин (за счет этого наследуется context и прокидывается cancellation). runBlocking же доступен отовсюду и не является extension функцией. 

Все упомянутые билдеры получают CoroutineScope.() лямбду на вход, внутри которой уже можно вызывать другие билдеры и suspend функции.


На этом всё! Удачи на собеседованиях 🙂

А если вам интересн такой формат подготовки и вы хотели бы серьезно поднять свои шансы на заветный оффер, то рекомендую попробовать курс «Android собеседования от А до Я: популярные вопросы и ответы к ним«. Курс содержит разбор более 350-и популярных технических вопросов, которые встречаются на реальных Android собеседованиях в крупные компании в РФ — Ozon, Tinkoff, Альфабанк, Сбер и др.


ссылка на оригинал статьи https://habr.com/ru/articles/873088/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *