{}const=>[]async()letfn</>var
ПрофессияРазработка

Вопросы на собеседовании Java junior: core, collections и код

Готовим Java Core к интервью: JVM, типы, String, equals и hashCode, ООП, коллекции, generics, исключения, потоки, тесты, SQL и практическая задача.

К

Кодик

Автор

6 мин чтения

Вопросы на собеседовании Java junior охватывают Java Core, ООП, equals и hashCode, Collections, generics, исключения, базовую многопоточность, тесты и SQL. Готовьтесь объяснять контракт и последствия выбора структуры, а не повторять определения JVM, List или Map без запускаемого примера.

Уточните используемую версию Java. Старый Oracle Tutorial прямо предупреждает, что примеры ориентированы на JDK 8, а современные руководства находятся на dev.java и в документации текущего JDK. Базовые контракты коллекций и исключений сохраняются, но синтаксис и API развиваются. Не называйте preview-функцию обычной возможностью без версии и флага компиляции. Сверяйте пример с компилятором целевого проекта и тестом.

1Core

Типы, String, class, interface, inheritance и exceptions.

2Collections

List, Set, Map, Queue, generics и выбор реализации.

3Runtime

JVM, memory, threads, resources и диагностика.

Порядок ответа Java: контракт, структура, код, тест
Порядок ответа про Java Core: сначала контракт equals и hashCode, затем выбор между List, Set и Map, потом запускаемый пример и тест на него.

Вопросы на собеседовании Java junior про equals и hashCode

Если объекты используются как ключи HashMap или элементы HashSet, равные по equals объекты обязаны иметь одинаковый hashCode. В record компилятор создаёт value-based equals и hashCode по компонентам. Для обычного класса контракт надо реализовать согласованно и не менять поля ключа, пока объект находится в hash-коллекции.

import java.util.HashSet;
import java.util.Set;

record UserId(long value) {}

public class Main {
    public static void main(String[] args) {
        Set<UserId> ids = new HashSet<>();
        ids.add(new UserId(42));
        ids.add(new UserId(42));

        // Одинаковые значения дают один элемент множества
        System.out.println(ids.size()); // 1
    }
}
Ожидаемый результат
  • HashSet содержит один UserId со значением 42
  • Кандидат связывает результат с equals и hashCode, а не только с Set

Следующий вопрос: почему Map не является подтипом Collection? У неё пары ключ-значение и отдельная ветка интерфейсов. Для List важен порядок и допустимы дубли, Set моделирует уникальность, Queue описывает обработку элементов, Map даёт доступ по ключу. Выбор ArrayList или LinkedList нельзя делать по названию: назовите операции, объём и фактические измерения.

🔥 100 000+ учеников уже с нами

Устал читать теорию?
Пора кодить!

Кодик — приложение, где ты учишься программировать через практику. AI-наставник, интерактивные уроки, реальные проекты.

🤖 AI 24/7
🎓 Сертификаты
💰 Бесплатно
🚀 Начать учиться
Присоединились сегодня

Основные блоки Java junior

ЭлементЧто означаетЧто делать
Типы и Stringprimitive, wrapper, immutability, poolПредсказать == и equals
ООПencapsulation, inheritance, polymorphismСпроектировать интерфейс
CollectionsList, Set, Map, QueueВыбрать структуру
Exceptionschecked, unchecked, try-with-resourcesЗакрыть ресурс
Concurrencythread, race, synchronized, executorОбъяснить общий доступ

Исключение - это объект, который нарушает нормальный ход выполнения. Checked exception нужно обработать или объявить, unchecked обычно указывает на ошибку использования API или программы. try-with-resources закрывает AutoCloseable ресурс. Не ловите Exception без плана восстановления. Для многопоточности сначала объясните race condition на общем изменяемом состоянии, затем способы убрать разделение или синхронизировать доступ.

Чем сильный ответ отличается: версия JDK, крайний случай, замер
Что добавляет сильный ответ к определению: версию JDK, крайний случай с null или дублем, способ закрыть ресурс через try-with-resources и измерение вместо догадки о скорости.

Практика: проверьте контракт equals и hashCode в HashSet

Соберите один файл Main.java и покажите на нём контракт equals и hashCode целиком. Успех: HashSet с двумя одинаковыми UserId печатает 1, тот же код на обычном классе без переопределений печатает 2, а после ручных equals и hashCode снова 1. Никаких фреймворков не нужно, хватит javac и консоли.

  1. record UserId в HashSet. В Main.java объявите record UserId(long value), добавьте в HashSet два раза new UserId(42) и напечатайте ids.size(). Консоль покажет 1: компилятор сгенерировал equals и hashCode по компоненту value.
  2. Класс без equals. Замените record обычным class UserId с полем value и конструктором, ничего не переопределяя. Тот же код напечатает 2, потому что унаследованный от Object equals сравнивает ссылки.
  3. Ручные equals и hashCode. Допишите в класс equals по полю value и hashCode через Objects.hash(value). Размер множества снова станет 1, и это ровно тот контракт, который record выдаёт бесплатно.
  4. Изменяемый ключ HashSet. Сделайте поле value изменяемым, положите объект в HashSet, поменяйте значение и вызовите ids.contains для того же объекта. Почти наверняка вернётся false: элемент лежит в корзине по старому hashCode, а ищут его по новому.
  5. Тест на контракт. Заверните проверки в JUnit-тест: assertEquals(1, ids.size()) и assertTrue(ids.contains(id)) до изменения поля. Зелёный тест закрепляет вывод и переживёт следующее переписывание класса.

Нарушьте контракт намеренно двумя способами. Сначала оставьте equals по value, а hashCode заставьте возвращать константу 1: множество продолжит работать правильно, но все элементы лягут в одну корзину и поиск станет линейным. Затем удалите hashCode совсем: два равных по equals UserId снова дадут size 2, потому что унаследованный hashCode считается от идентичности объекта.

Критерий готовности. Вы можете объяснить, почему size равен 1 или 2 в каждом из вариантов, и назвать, что HashSet проверяет раньше: hashCode или equals. Подтверждение: три запуска с выводами 1, 2 и снова 1 плюс зелёный тест на contains. Отдельно скажите, какие поля объекта нельзя менять, пока он лежит в hash-коллекции.

Перенесите тот же разбор на HashMap: положите UserId ключом и посмотрите, что вернёт get после изменения поля. Дальше сравните HashMap с TreeMap там, где нужен порядок ключей, и с ConcurrentHashMap там, где к карте идут несколько потоков. Для каждой замены называйте операцию и объём данных, иначе ответ снова превратится в перечисление классов.

Частые ошибки и почему они появляются

Кандидат может знать названия всех коллекций, но выбрать HashMap там, где нужен отсортированный порядок или безопасный конкурентный доступ. Вторая ошибка: объяснять сборщик мусора как немедленное освобождение любого ресурса. Файлы и соединения закрывают детерминированно. Третья: заявлять потокобезопасность по одному использованию final, хотя изменяемый объект всё ещё разделяется.

Учить только определения

Для каждой темы решите маленькую задачу и напишите тест.

Не уточнять JDK

Версия влияет на синтаксис, API и доступность features.

Игнорировать контракт

Объясняйте порядок, дубли, null, mutability и concurrency.

Самопроверка

Почему equals и hashCode переопределяют вместе?

equals и hashCode работают в паре: HashMap и HashSet сначала находят корзину по hashCode и только внутри неё сравнивают объекты через equals. Если переопределить один метод и забыть второй, равные объекты попадут в разные корзины, и коллекция будет считать их разными.

Почему Map не входит в Collection?

Map не наследует Collection, потому что хранит пары ключ-значение, а Collection описывает набор одиночных элементов. Доступ к содержимому Map дают отдельные представления: keySet, values и entrySet.

Зачем try-with-resources, если есть finally?

try-with-resources закрывает каждый AutoCloseable ресурс сам, в обратном порядке объявления, и делает это даже когда из тела вылетело исключение. Ручной finally умеет то же самое, но его легко написать с ошибкой, особенно если ресурсов несколько или закрытие само бросает исключение.

Что компилятор генерирует для record?

Для record компилятор генерирует конструктор по компонентам, методы доступа, toString, а также equals и hashCode по всем компонентам. Поэтому record удобен как ключ HashMap: контракт согласован сразу, а компоненты неизменяемы.

Что выбрать: ArrayList или LinkedList?

ArrayList и LinkedList выбирают по операциям, а не по названию: ArrayList даёт дешёвый доступ по индексу и плотное размещение в памяти, LinkedList выигрывает разве что на вставках и удалениях через уже полученный итератор. В обычных задачах ArrayList оказывается предпочтительнее, а спорный случай закрывают измерением на своих объёмах.

Освобождает ли сборщик мусора файлы и соединения?

Сборщик мусора освобождает память объектов и ничего не обещает про файл, сокет или соединение с базой. Такие ресурсы закрывают детерминированно через try-with-resources или явный close, иначе дескрипторы кончатся раньше, чем память.

Что делать дальше

Соберите 20 карточек Core, но на обратной стороне пишите не определение, а пример и тест. Последовательную практику даёт курс Java. Срок подготовки оцените по плану до junior, а общие алгоритмы потренируйте на задачах с массивами и Map.

🎯Хватит откладывать

Понравилась статья?
Пора применять на практике!

В Кодик ты не просто читаешь — ты сразу пишешь код. Теория + практика = реальный скилл.

Мгновенная практика
🧠AI объяснит код
🏆Сертификат

Без регистрации • Без карты