Вопросы и задачи на собеседовании по Java в 2026 году
Вопросы и задачи на собеседовании по Java в 2026 году
Рассказываем, какие темы стоит повторить перед собеседованием на позицию Java-разработчика.
Проходить собеседования и быть готовым к самым сложным вопросам учат на курсе «Java-разработчик». За 10 месяцев студенты осваивают профессию и получают помощь в поиске работы. Выпускникам помогают оформить портфолио и правильно себя презентовать.
| Вопросы | Ответы |
| Чем отличаются JVM, JRE и JDK? | JVM (Java Virtual Machine) — это среда выполнения: она загружает классы, проверяет байткод, выполняет его (в том числе через JIT-компиляцию), управляет памятью и потоками и отвечает за runtime-механизмы вроде сборки мусора.
JRE (Java Runtime Environment) — это всё, что нужно, чтобы запустить Java-приложение: сама JVM + стандартные библиотеки и runtime-компоненты (то есть без инструментов разработки). JDK (Java Development Kit) — это комплект для разработки: включает JRE и добавляет компилятор javac, отладчик и другие утилиты (например, для сборки, диагностики и анализа), то есть всё, что нужно, чтобы писать, собирать и исследовать приложение. |
| На какой версии Java вы работали? Что поменялось в Java 8/11/17/21? | Во-первых, после Java 8 рынок в основном ориентируется на LTS-релизы (11/17/21), поэтому апгрейды стали регулярной частью поддержки: важно держать зависимости совместимыми и планировать обновления.
Во-вторых, начиная с Java 9 появилась модульная система (JPMS) и ужесточился доступ к внутренним API JDK — поэтому при миграциях иногда возникают проблемы с библиотеками и рефлексией и много времени уходит на обновление экосистемы и сборки. В-третьих, язык и стандартная библиотека заметно эволюционировали в сторону более компактного и безопасного кода: records упрощают DTO и value-объекты, sealed classes позволяют контролировать иерархии, современный switch/pattern matching снижает объём шаблонного кода. В Java 21 отдельно выделяются virtual threads (Loom) — это меняет подход к конкурентному коду в задачах с большим количеством блокирующих операций. |
| Что такое bytecode? | Bytecode — это промежуточный «машиночитаемый» формат .class, который получается после компиляции Java-кода. Он не привязан к конкретной ОС или процессору. |
| Был ли опыт миграции между версиями Java? Какие есть риски? | Чаще всего риски не в синтаксисе, а в окружении: несовместимые зависимости, проблемы из-за модулей и доступа к внутренним API (Java 9+) и рантайм-нюансы (параметры JVM, контейнеры, возможные регрессии). Обычно миграция — это обновление библиотек, прогон тестов и внимательный мониторинг после выката. |
Отдельно вспомните базовую модель памяти JVM: чем отличаются stack и heap, что хранится в Metaspace и почему объекты в Java создаются в heap, а в stack обычно лежат ссылки и данные вызова метода.
По GC важно знать, какие сборщики бывают: Serial, Parallel, G1 и ZGC. Ещё нужно на базовом уровне понимать, как вообще работает сборка мусора: программа создаёт объекты, часть из них со временем становится не нужна, GC находит такие объекты и освобождает память, чтобы её можно было снова использовать.
| Вопросы | Ответы |
| Overload и override — в чём разница? | Overload — это методы с одним именем, но с разными параметрами; выбор происходит на этапе компиляции.
Override — переопределение метода в наследнике; выбирается в рантайме через полиморфизм. |
| Checked- и unchecked-исключения — когда что использовать? | Checked-исключения заставляют явно обрабатывать ошибку и влияют на API. Unchecked обычно используют для ошибок программирования или ситуаций, которые невозможно или не нужно корректно обрабатывать на уровне вызывающего кода. Выбор зависит от того, ожидаемая это ветка поведения или аварийная. |
| Что такое generics и зачем нужны wildcard’ы? | Generics нужны, чтобы обеспечить типобезопасность на этапе компиляции и избавиться от лишних кастов и ClassCastException в рантайме.
При этом List<Dog> не является List<Animal>, потому что в Java обобщённые типы не поднимаются по наследованию: иначе можно было бы добавить Cat в список собак через ссылку типа List<Animal>. Wildcard’ы позволяют писать более гибкие API, которые принимают семейство типов, а не один конкретный. ? extends T используют, когда коллекция выступает «источником» значений (в основном читаем), поэтому безопасно читать T, но добавлять нельзя. ? super T используют, когда коллекция «принимает» значения (в основном пишем): можно добавлять T, но при чтении гарантирован только Object (PECS). |
| Зачем нужен контракт equals/hashCode? | Чтобы корректно определять логическое равенство объектов. У equals есть строгий контракт (рефлексивность, симметричность, транзитивность), а hashCode обязан быть с ним согласован. В этом месте много подводных камней: важно выбирать стабильные поля для сравнения и понимать, как устроить hashCode, чтобы он был и корректным, и качественным (например, не собирать его из полей, которые могут меняться, и не делать его слишком примитивным, чтобы не провоцировать коллизии).
Чаще всего после этого вопроса интервьюер логично переходит к теме коллекций — так как именно от equals/hashCode зависит поведение HashMap и HashSet и то, что происходит, если ключ внезапно «изменился». Про это — в следующем блоке. |
Восполните знания по строкам: == vs equals, String immutability, String pool, разницу между строковыми литералами и new String (), почему конкатенация в цикле — плохая идея (и когда включается StringBuilder).
Отдельно повторите Optional: зачем он вообще появился, как его правильно использовать в API и почему Optional обычно не делают полями сущностей/DTO. Полезно вспомнить самые частые операции и то, в каких местах они реально упрощают код, а где только мешают.
| Вопросы | Ответы |
| ArrayList или LinkedList — что выбрать? | В большинстве случаев — ArrayList. Он обычно быстрее и экономнее по памяти, потому что элементы лежат рядом и лучше работают с CPU cache. LinkedList имеет смысл в редких сценариях с частыми вставками/удалениями в середине, когда позиция уже найдена, но на практике его выбирают заметно реже, чем кажется. |
| HashMap и TreeMap — чем отличаются? | HashMap даёт средний доступ O (1) без упорядочивания. TreeMap хранит ключи отсортированными, и операции идут за O (log n). Если нужен порядок, диапазонные запросы или «найти ближайший ключ» — TreeMap оправдан. |
| Как работает HashMap внутри? | HashMap берёт hashCode () ключа, превращает его в индекс и по нему выбирает корзину (bucket). Если разные ключи попали в одну и ту же корзину, это коллизия: тогда внутри корзины элементы хранятся вместе и при поиске дополнительно сравниваются через equals (). В современных версиях Java при большом количестве коллизий корзина может «усложниться» (из списка превратиться в дерево), чтобы поиск не становился слишком медленным. Когда карта вырастает выше порога (capacity × load factor), она делает resize: увеличивает внутренний массив и перераспределяет элементы, поэтому это «дорогая» операция. Поэтому hashCode важен по двум причинам: он должен быть согласован с equals, и он должен хорошо распределять ключи, чтобы коллизий было мало и доступ оставался близким к O (1).
Про HashMap вообще можно задать очень много уточняющих вопросов, и интервьюеры этим часто пользуются. Например, как именно она хранится в памяти, что происходит при resize и почему это может внезапно ударить по производительности, чем плохой hashCode опасен не только логически, но и практически. Почти всегда всплывает тема ключей: какие объекты можно использовать в качестве ключа, почему они должны быть логически неизменяемыми и что ломается, если ключ меняется после добавления в карту. Отсюда же обычно уходят в разговор про immutability в целом — зачем делать объекты неизменяемыми, как это упрощает работу с коллекциями и многопоточностью. |
| Вопросы | Ответы |
| Как создать поток в Java? | Либо создать Thread и передать ему Runnable, либо использовать ExecutorService и отправлять задачи в пул. В современных проектах чаще используют пулы, потому что они управляют количеством потоков и очередью задач. |
| Что такое состояние гонки (race condition)? | Это ситуация, когда несколько потоков одновременно читают и изменяют общие данные и результат зависит от порядка выполнения. В итоге состояние может стать неправильным даже при правильном на вид коде. |
| Что такое deadlock? | Взаимная блокировка: два (или больше) потока постоянно ждут друг друга, потому что каждый держит ресурс, который нужен другому, и не может продолжить. |
| Как обеспечить синхронизацию? | Нужно защитить общий ресурс так, чтобы в критической секции был только один поток и чтобы изменения были видны другим потокам. Для этого используют synchronized, локи, атомарные типы (Atomic*) и потокобезопасные структуры данных — выбор зависит от задачи. |
| Что такое локи (locks)? | Это явные механизмы блокировки, которые работают похожим образом на synchronized, но дают больше контроля: можно попробовать взять блокировку с таймаутом, освобождать в нужном месте, использовать разные режимы (например, read/write). |
| Что такое ExecutorService? | Это интерфейс для запуска задач в пуле потоков. Он управляет потоками и очередью: позволяет ограничивать параллелизм, отправлять задачи, получать результат (Future), задавать таймауты и корректно завершать выполнение. |
| Чем Runnable отличается от Callable? | Runnable — это задача, которая ничего не возвращает и не бросает checked-исключения: у неё метод run () без результата. Callable — задача, которая возвращает результат (метод call () возвращает T) и может бросать checked-исключения. В ExecutorService Runnable подходит для «просто выполнить», а Callable — когда нужен результат, который потом можно получить через Future. |
Дальше повторите основные инструменты Java: как создавать и запускать потоки (Thread, Runnable, Callable), как управлять выполнением задач через ExecutorService и пулы потоков, какие гарантии дают synchronized и volatile. Полезно руками написать несколько коротких примеров, чтобы уверенно объяснять, как выглядит синхронизация в коде и где обычно допускают ошибки. Отдельно освежите потокобезопасные структуры данных: какие коллекции считаются thread-safe, какие реализации есть в java.util.concurrent и когда их использование снимает необходимость в ручной синхронизации.
| Вопросы | Ответы |
| map и flatMap — в чём разница? | map используют, когда каждому элементу соответствует один результат, а flatMap — когда одному элементу соответствует несколько результатов и их нужно объединить в один общий список, а не получить «список списков». |
| Какие бывают операции в Stream API? | Операции делятся на промежуточные и терминальные. Промежуточные (map, filter, sorted) возвращают новый stream и не выполняются сразу. Терминальные (collect, reduce, forEach, count) запускают выполнение и дают результат. |
| Почему parallelStream не всегда быстрее? | Потому что распараллеливание означает накладные расходы: разбиение работы, синхронизацию и сбор результата. На небольших объёмах данных или при операциях с ожиданием это часто только замедляет выполнение. |
| Что такое функциональный интерфейс в Java? | Это интерфейс с одним абстрактным методом, который можно реализовать помощью лямбды. В Java есть готовые функциональные интерфейсы в java.util.function, например Predicate (проверка условия), Function (преобразование), Supplier (поставщик значения), Consumer (обработка без результата), а также варианты для примитивов (IntPredicate, LongFunction и т. д.). Аннотация @FunctionalInterface не обязательна, но помогает зафиксировать контракт и ловить ошибки при изменениях. |
| Что такое method reference и чем он отличается от лямбды? | Это более короткая запись той же идеи, когда сигнатура совпадает. По смыслу то же самое, разница — в читаемости. |
| Можно ли перегружать методы, принимающие разные функциональные интерфейсы? | Да, но легко получить неоднозначность при вызове с лямбдой: компилятор может не понять, какую перегрузку выбрать. Тогда приходится явно указывать тип или использовать cast. |
По функциональному стилю достаточно освежить лямбды и самые частые функциональные интерфейсы (Predicate, Function, Consumer, Supplier) и пару раз написать код с method reference. В этом блоке часто дают маленькие задания «написать стрим-цепочку», поэтому лучше заранее потренироваться руками, чтобы не вспоминать синтаксис на интервью.
| Вопросы | Ответы |
| Жизненный цикл бина — что происходит от создания до готовности? | Spring создаёт объект бина, потом заполняет ему зависимости. После этого выполняется инициализация — например, метод с @PostConstruct или заданный init-метод. Когда приложение завершается и контекст закрывается, Spring вызывает методы завершения — например, @PreDestroy или destroy-метод. Запомните, что иногда Spring отдаёт не сам объект, а прокси вокруг него (например, для транзакций и AOP), поэтому то, «что реально вызывается», может отличаться от прямого вызова метода. |
| Чем отличаются @Component, @Service, @Repository? | Все три аннотации регистрируют класс как Spring-компонент. Разница в назначении и в некоторых механизмах: @Service обычно ставят на бизнес-логику, @Repository — на слой доступа к данным, Spring может выполнять перевод исключений из JDBC/JPA в свои исключения. @Component — общий вариант без дополнительного смысла. |
| Зачем нужна @Transactional и как она работает? | Она нужна, чтобы выполнять операции с БД в транзакции: либо всё фиксируется, либо откатывается. В Spring транзакции чаще всего подключаются через прокси: при вызове метода через Spring-бин открывается транзакция, а после выполнения происходит commit или rollback — в зависимости от результата и типа исключения. |
| Что такое dependency injection и какие виды инъекции бывают? Что лучше? | DI — это когда зависимости передаются объекту извне, а не создаются внутри. Основные варианты: инъекция через конструктор, сеттер и поле. Чаще всего предпочитают конструктор: зависимости явные, объект проще сделать корректно инициализированным, его удобнее тестировать. |
| Что такое AOP и зачем нужны advice? | AOP позволяет добавлять общий код «вокруг» вызова методов без дублирования в каждом классе: логирование, метрики, безопасность, транзакции. advice — это правило, что выполнить относительно вызова метода: до (before), после (after), при исключении (afterThrowing) или обернуть вызов целиком (around) и контролировать выполнение. |
| Как сделать глобальный обработчик ошибок в Spring? | Обычно используют @ControllerAdvice / @RestControllerAdvice и методы с @ExceptionHandler, которые ловят нужные исключения и возвращают единый формат ответа (статус, сообщение, детали). Это помогает сохранять обработку ошибок централизованной и одинаковой для всех контроллеров. |
| Вопросы | Ответы |
| Зачем нужны индексы? Какие у них плюсы и минусы? | Индексы нужны, чтобы база могла быстрее находить строки по условиям в WHERE, JOIN, ORDER BY. Плюс: запросы на чтение становятся заметно быстрее. Минусы: индексы занимают место и замедляют запись — при INSERT/UPDATE/DELETE их тоже нужно обновлять. Поэтому индексы — это всегда компромисс между скоростью чтения и стоимостью записи. |
| Какие типы индексов бывают? | Самые распространённые — B-tree (универсальный вариант для большинства запросов), Hash (быстрые по точному равенству, но редко используются в проде), составные индексы (по нескольким колонкам) и частичные индексы (по условию). В некоторых СУБД есть специализированные варианты — например, GIN/GiST для JSON и полнотекстового поиска. На интервью обычно ожидают, что ты понимаешь, чем составной индекс отличается от обычного и почему порядок колонок в нём важен. |
| Что такое N+1 и как от него избавиться? | Это ситуация, когда сначала загружается список сущностей одним запросом, а потом для каждой сущности отдельно подгружаются связанные данные — и запросов становится N+1. В JPA это решают через fetch join, @EntityGraph, batch fetching или пересмотр запроса так, чтобы нужные данные доставались сразу. Иногда проще изменить DTO и не тянуть лишние связи. |
| Как оптимизировать сложный SQL-запрос? | Обычно начинают с плана запроса (EXPLAIN): смотрят, какие индексы используются, где идут full scan и «дорогие» JOIN’ы. Дальше упрощают сам запрос: убирают лишние JOIN’ы и поля, добавляют или меняют индексы, переписывают подзапросы в JOIN’ы (или наоборот), проверяют селективность условий и актуальность статистики. |
Читать также: