Собеседование Java-разработчика охватывает семантику языка, коллекции, многопоточность, Spring и умение рассуждать о JVM. Ниже — вопросы, которые задают чаще всего, каждый с эталонным ответом. Junior: базовая теория, определения и простые практические кейсы.
1
Как устроен HashMap внутри и чем от него отличается ConcurrentHashMap?
Ответ
HashMap хранит записи в массиве бакетов, индекс берётся из хеша ключа; коллизии складываются в связный список, который после восьми узлов превращается в красно-чёрное дерево. Он не потокобезопасен — одновременный ресайз может испортить структуру. ConcurrentHashMap достигает потокобезопасности блокировкой только той корзины, в которую пишут (CAS плюс synchronized на узле), а не всей мапы, поэтому чтения идут без блокировок, а записи конкурируют только в пределах одной корзины.
2
Объясните контракт equals() и hashCode(). Что ломается при его нарушении?
Ответ
Если два объекта равны по equals(), они обязаны возвращать одинаковый hashCode; неравные объекты могут совпадать по хешу, но в идеале не совпадают. Нарушение ломает все хеш-коллекции: объект попадает в один бакет, а последующий поиск считает другой хеш, идёт в другой бакет и сообщает, что записи нет. Классический баг — изменить поле, участвующее в hashCode, уже после добавления объекта в множество.
3
Что такое garbage collection и какие сборщики есть в JVM?
Ответ
GC освобождает память кучи для объектов, до которых больше нельзя добраться от GC roots. Куча поколенческая — большинство объектов умирают молодыми, поэтому минорные сборки в young generation дёшевы. Из сборщиков есть Serial и Parallel для пропускной способности, G1 как современный дефолт с балансом паузы и throughput, а также ZGC и Shenandoah для очень больших куч с паузами меньше миллисекунды.
4
В чём разница между checked и unchecked исключениями?
Ответ
Checked наследуются от Exception и обязаны быть объявлены или обработаны — они описывают восстановимые ситуации, к которым вызывающий код должен готовиться, например IOException. Unchecked наследуются от RuntimeException и сигналят об ошибках программиста: NullPointerException, IllegalArgumentException. На практике совет такой: unchecked для багов, checked умеренно, потому что принуждение обрабатывать исключение в каждом вызове чаще всего рождает пустые catch-блоки.
5
Что такое Dependency Injection в Spring и какие есть типы инъекции?
Ответ
DI означает, что объект получает зависимости от контейнера, а не создаёт их сам, — это развязывает классы и делает их тестируемыми. Spring поддерживает инъекцию через конструктор, сеттер и поле. Предпочтительна конструкторная: зависимости становятся final, объект никогда не существует в недостроенном виде, и класс не может скрыть разрастающийся список зависимостей так, как это позволяет инъекция в поле.
6
В чём разница между @Component, @Service, @Repository и @Controller?
Ответ
Все четыре регистрируют класс как бин Spring и технически взаимозаменяемы для сканирования. Различаются намерением и тем, что Spring к ним добавляет: @Repository транслирует исключения персистентности в иерархию DataAccessException, @Controller и @RestController участвуют в маппинге запросов, а @Service — семантическая пометка бизнес-логики. Использование конкретной аннотации документирует слой и включает нужное поведение.
7
Что такое транзакция? Объясните уровни изоляции.
Ответ
Транзакция — это единица работы, удовлетворяющая ACID: она либо целиком коммитится, либо откатывается. Уровни изоляции меняют консистентность на параллелизм: Read Uncommitted допускает грязные чтения, Read Committed их исключает, Repeatable Read дополнительно исключает неповторяющиеся чтения, Serializable убирает и фантомы ценой пропускной способности. Большинство систем работают на Read Committed и закрывают остаточные аномалии оптимистичными блокировками.
8
В чём разница между ArrayList и LinkedList? Когда выбрать каждый?
Ответ
ArrayList опирается на расширяемый массив: доступ по индексу O(1), но вставка и удаление в середине сдвигают элементы. LinkedList — двусвязный список: вставка и удаление у известного узла O(1), зато доступ по индексу O(n), и каждый элемент несёт накладные расходы узла. На практике ArrayList выигрывает почти всегда, потому что локальность кеша процессора важнее теоретической сложности; LinkedList полезен в основном как Deque.
9
Что такое volatile и synchronized? Когда использовать каждый?
Ответ
volatile гарантирует видимость — запись сразу видна другим потокам, а чтения не кешируются — но не даёт атомарности, поэтому volatile-счётчик всё равно теряет инкременты. synchronized даёт и видимость, и взаимное исключение, так что блок в каждый момент выполняет только один поток. volatile берут для простого флага, который читают многие потоки; synchronized или Atomic — когда операция это чтение-изменение-запись.
🦎
Прочитать ответы недостаточно
На собеседовании ты говоришь вслух под давлением. Кем задаст эти же вопросы, оценит каждый ответ и покажет, что именно подтянуть.
Пройти интервью Junior Java Backend →Бесплатно · 3 интервью в месяц