Вопросы на собеседовании: Java-разработчик
100 реальных вопросов с образцовыми ответами и пояснениями для уровня Junior.
Смотреть пример резюме: Java-разработчик →Тренировка флешкарточками
Интервальное повторение · Hunter Pass
Вопросы
JDK предоставляет инструменты разработки, JVM исполняет Java-байткод, а JRE содержит всё необходимое для этого исполнения.
- JDK включает такие инструменты, как компилятор javac, а также компоненты среды выполнения.
- javac компилирует исходные Java-файлы в платформонезависимый байткод в файлах .class.
- JVM загружает и исполняет этот байткод в конкретной операционной системе.
- Под JRE традиционно понимают JVM вместе с библиотеками среды выполнения, хотя современные версии Java обычно поставляются как JDK или специальные образы среды выполнения.
Зачем это спрашивают: Интервьюер проверяет, различаете ли вы компилятор, среду выполнения и виртуальную машину, а не считаете их синонимами.
Java считается платформонезависимым языком, потому что исходный код компилируется в байткод, который могут исполнять разные реализации JVM.
- Компилятор создаёт инструкции для JVM, а не машинный код конкретной операционной системы.
- Для каждой поддерживаемой платформы существует своя JVM, которая интерпретирует или компилирует один и тот же байткод.
- Переносимость всё же зависит от того, не использует ли программа API конкретной операционной системы и нативные библиотеки.
Зачем это спрашивают: Сильный ответ связывает переносимость с байткодом и платформенными реализациями JVM, а не просто повторяет известный слоган.
Метод main служит стандартной точкой входа, которую Java Launcher вызывает для запуска приложения.
- Обычно он объявляется как public static void main(String[] args).
- public делает метод доступным для запуска, а static позволяет вызвать его без создания объекта.
- String[] args содержит аргументы командной строки, а void означает, что метод не возвращает вызывающей стороне значение.
Зачем это спрашивают: Интервьюер хочет понять, знаете ли вы назначение частей сигнатуры точки входа, а не только помните её наизусть.
Объявление вводит переменную и её тип, а инициализация присваивает ей первое значение.
- int count; объявляет локальную переменную с именем count.
- count = 0; присваивает значение, а int count = 0; совмещает объявление с инициализацией.
- Локальную переменную нужно гарантированно инициализировать до использования, и компилятор это проверяет.
Зачем это спрашивают: Вопрос проверяет знание базового синтаксиса и правила обязательной инициализации локальных переменных на этапе компиляции.
В Java есть восемь примитивных типов значений: byte, short, int, long, float, double, char и boolean.
- byte, short, int и long представляют знаковые целые числа с разными диапазонами.
- float и double представляют числа с плавающей точкой, причём double обеспечивает более высокую точность.
- char хранит одну кодовую единицу UTF-16, а boolean принимает значение true или false.
Зачем это спрашивают: Интервьюер оценивает, знаете ли вы категории примитивов и назначение каждого типа в системе типов Java.
Переменная примитивного типа содержит простое значение, а ссылочная переменная указывает на объект или содержит null.
- Примитивы имеют заданные языком типы и не предоставляют экземплярные методы.
- Объекты создаются на основе классов и содержат поля и поведение, доступные через ссылку.
- При присваивании примитива копируется его значение, а при присваивании ссылки копируется ссылка на тот же объект.
Зачем это спрашивают: Хороший ответ различает значения и ссылки и объясняет наблюдаемый результат присваивания.
Экземплярные и статические поля получают значения по умолчанию, а локальные переменные нужно явно инициализировать до использования.
- Числовые поля получают ноль, поля boolean получают false, а ссылочные поля получают null.
- Элементы массива тоже получают значение по умолчанию для своего типа.
- Компилятор отклоняет код, если по какому-либо пути выполнения читается неинициализированная локальная переменная.
Зачем это спрашивают: Интервьюер проверяет важное различие между инициализацией состояния объекта и правилами для локальных переменных.
Расширяющее преобразование примитивов Java разрешает выполнять неявно, а сужающее направлено к типу, для которого требуется явное приведение.
- Преобразование int в long является расширяющим и сохраняет любое возможное значение int.
- Преобразование long в int является сужающим, потому что int не охватывает весь диапазон long.
- Сужение может вызвать переполнение или потерю точности, причём даже расширение int в float способно потерять числовую точность.
Зачем это спрашивают: Сильный ответ объясняет и поведение компилятора, и риск потери данных.
Автоупаковка автоматически преобразует примитив в соответствующий класс-обёртку, а автораспаковка извлекает из обёртки примитивное значение.
- При присваивании int переменной Integer может сработать автоупаковка через Integer.valueOf.
- При присваивании Integer переменной int может сработать автораспаковка через intValue.
- Распаковка обёртки со значением null вызывает NullPointerException, поэтому нужно учитывать возможность null.
Зачем это спрашивают: Интервьюер проверяет, понимаете ли вы удобство преобразований обёрток и связанный с null риск.
Для примитивов == сравнивает значения, а для ссылок на объекты проверяет, указывают ли обе ссылки на один объект.
- Два разных объекта могут содержать одинаковые данные, но сравнение через == всё равно даст false.
- Логическое равенство объектов обычно проверяют методом equals.
- При сравнении обёртки с примитивом может произойти автораспаковка, которая скрывает различие между сравнением идентичности и значений.
Зачем это спрашивают: Вопрос проверяет, умеете ли вы избегать распространённой ошибки Java, связанной со смешением идентичности и логического равенства.
String является неизменяемым, потому что содержимое строки нельзя изменить после создания объекта.
- Операции concat, replace и toUpperCase возвращают новую строку, а не изменяют исходную.
- Неизменяемость позволяет безопасно совместно использовать и кэшировать строки, а также применять их как ключи Map со стабильным равенством.
- Многократная конкатенация в цикле создаёт много временных объектов, поэтому там обычно лучше использовать изменяемый построитель строк.
Зачем это спрашивают: Интервьюер ожидает практические следствия неизменяемости, а не только её определение.
Пул строк представляет собой управляемое JVM хранилище, благодаря которому одинаковые интернированные строки могут использовать один объект.
- Строковые литералы с одинаковым содержимым обычно ссылаются на один экземпляр из пула.
- new String("java") явно создаёт отдельный объект, даже если такой литерал уже есть в пуле.
- Пул экономит память, но содержимое строк всё равно следует сравнивать через equals, не полагаясь на идентичность ссылок.
Зачем это спрашивают: Сильный ответ объясняет работу пула и не делает ошибочный вывод, что строки безопасно сравнивать через ==.
StringBuilder стоит использовать, когда текст многократно изменяется или собирается из частей в одном потоке.
- append и другие методы меняют тот же построитель, а не создают новую строку на каждом шаге.
- Это сокращает количество временных объектов в циклах и при объединении множества фрагментов.
- После завершения сборки результат преобразуют в неизменяемый String методом toString.
Зачем это спрашивают: Интервьюер проверяет, можете ли вы связать неизменяемость String с подходящим инструментом для сборки текста.
Класс определяет состояние и поведение типа, а объект является созданным во время выполнения экземпляром этого класса.
- Поля описывают данные, которые может хранить каждый экземпляр.
- Методы описывают операции, доступные экземплярам или самому классу.
- Несколько объектов одного класса имеют одинаковую структуру, но могут хранить разные значения полей.
Зачем это спрашивают: Этот базовый вопрос проверяет, различаете ли вы определение типа и созданные на его основе экземпляры.
Конструктор инициализирует новый объект, совпадает по имени с классом и не имеет возвращаемого типа.
- Выражение new выделяет память под объект и вызывает подходящий конструктор.
- Конструкторы можно перегружать, задавая разные списки параметров.
- Если класс не объявляет ни одного конструктора, компилятор может добавить конструктор без аргументов по умолчанию.
Зачем это спрашивают: Интервьюер оценивает, понимаете ли вы инициализацию объектов и точные отличия конструктора от метода.
this ссылается на текущий объект, для которого выполняется экземплярный метод или конструктор.
- Оно помогает отличить поле от одноимённого параметра, например в выражении this.name = name.
- this(...) вызывает другой конструктор того же класса и должен быть первым оператором конструктора.
- В статическом контексте this использовать нельзя, потому что там нет текущего экземпляра.
Зачем это спрашивают: Сильный ответ охватывает доступ к текущему экземпляру, делегирование конструкторов и ограничение статического контекста.
Статический член принадлежит классу, а не отдельному экземпляру.
- Все экземпляры видят одно статическое поле, поэтому оно подходит для общего состояния класса или констант.
- Статический метод можно вызвать через имя класса без создания объекта.
- Статический код не может напрямую обращаться к экземплярным полям и методам, потому что у него нет ссылки this.
Зачем это спрашивают: Интервьюер проверяет, понимаете ли вы принадлежность и правила доступа для членов класса.
В зависимости от места применения final запрещает повторное присваивание, переопределение метода или наследование класса.
- Переменной final можно присвоить значение только один раз, но ссылка final не делает сам объект неизменяемым.
- Метод final нельзя переопределить в подклассе.
- От класса final нельзя наследоваться, что помогает сохранить его поведение и инварианты.
Зачем это спрашивают: Хороший ответ различает три применения final и не приравнивает неизменяемую ссылку к неизменяемому объекту.
Инкапсуляция скрывает внутреннее состояние объекта за контролируемым публичным интерфейсом.
- Поля часто делают private, чтобы вызывающий код не мог свободно привести объект к недопустимому состоянию.
- Методы могут проверять изменения и сохранять инварианты класса.
- Вызывающий код зависит от стабильного поведения, а не от текущего способа хранения данных, поэтому внутреннюю реализацию проще менять.
Зачем это спрашивают: Интервьюер хочет услышать, как контроль доступа защищает инварианты, а не только упоминание геттеров и сеттеров.
Наследование позволяет подклассу повторно использовать и специализировать доступное поведение одного суперкласса.
- Класс объявляет отношение через extends и наследует доступные поля и методы.
- Конструкторы не наследуются, а конструктор подкласса явно или неявно вызывает конструктор суперкласса.
- У каждого класса, кроме Object, только один непосредственный суперкласс, потому что Java не поддерживает множественное наследование классов.
Зачем это спрашивают: Сильный ответ включает правило одиночного наследования в Java и особое поведение конструкторов.
Закрытые вопросы
- 21
Чем перегрузка метода отличается от его переопределения?
oopmethods - 22
Что такое полиморфизм времени выполнения в Java?
oop - 23
Что такое абстрактный класс?
oop - 24
Что такое интерфейс в Java?
typesinterfaces - 25
Когда стоит выбрать интерфейс, а когда абстрактный класс?
typesoopinterfaces - 26
Чем отличаются уровни доступа public, protected, package-private и private в Java?
basics - 27
Для чего в Java нужны пакеты и объявления import?
basics - 28
Почему композицию часто предпочитают наследованию?
oopownership - 29
Какое значение имеет класс Object в Java?
- 30
Какой контракт должны соблюдать equals и hashCode?
equals-hashcode - 31
Зачем переопределять toString в Java-классе?
methods - 32
Какие гарантии предоставляет интерфейс List?
typesinterfaces - 33
Чем отличаются ArrayList и LinkedList?
collections - 34
Чем Set отличается от других типов коллекций?
collections - 35
Как HashSet определяет, что элемент является дубликатом?
collections - 36
Как Map представляет связи между ключами и значениями?
- 37
Как HashMap работает на базовом уровне?
collections - 38
Чем массивы отличаются от ArrayList в Java?
collections - 39
Какими распространёнными способами можно обходить коллекцию в Java?
iterationcollections - 40
Какую проблему решают дженерики в Java?
generics - 41
Почему List<Integer> не является подтипом List<Number>?
- 42
Что такое сырые типы и почему их следует избегать в современном Java-коде?
generics - 43
Чем проверяемые исключения отличаются от непроверяемых?
error-handlingexceptions - 44
Как совместно работают try, catch и finally?
modifiersexceptions - 45
Чем throw отличается от throws в Java?
- 46
Когда следует создавать собственное исключение?
error-handlingexceptions - 47
Что делает try-with-resources?
exceptions - 48
Для чего используются стек и куча в работающей Java-программе?
memorydata-structures - 49
Что делает сборка мусора в JVM?
gcjvmcollections - 50
Java передаёт аргументы по значению или по ссылке?
- 51
Как бы вы реализовали метод нормализации имени пользователя перед сохранением?
normalization - 52
Как написать логику суммирования только положительных целых чисел в списке с безопасной обработкой null вместо списка?
fundamentals - 53
Как удалить повторяющиеся email-адреса, сохранив исходный порядок?
- 54
Как посчитать частоту слов в предложении с помощью коллекций Java?
collections - 55
Как сгруппировать список заказов по идентификатору клиента?
- 56
Как отсортировать сотрудников сначала по убыванию зарплаты, а затем по возрастанию имени?
- 57
Как объединить две map остатков товаров, складывая количества для совпадающих идентификаторов?
- 58
Как удалить истёкшие сессии из изменяемого списка без ConcurrentModificationException?
sessionsconcurrency - 59
Как реализовать FIFO-очередь фоновых задач стандартными коллекциями Java?
data-structurescollectionsjobs - 60
Как найти пересечение двух списков без повторяющихся значений в результате?
- 61
Как вернуть три самых частых кода ошибок из списка?
- 62
Поиск пользователя в map иногда приводит к NPE. Как найти и исправить причину?
- 63
Как диагностировать ClassCastException при чтении значений из старой Map без типов?
- 64
Почему добавление элемента в List.of может упасть во время выполнения и как исправить код?
- 65
HashMap не находит объект-ключ, который выглядит равным сохранённому. Что нужно проверить?
collections - 66
Как реализовать проверку возраста с собственным исключением?
error-handlingexceptionsvalidation - 67
Как прочитать текстовый файл и гарантировать его закрытие при ошибке разбора?
- 68
Как разобрать список строк с числами, если неверные элементы нужно сообщить, а корректные сохранить?
strings - 69
На каком уровне следует ловить исключение из метода репозитория?
error-handlingexceptions - 70
Как сохранить полезные данные для отладки при преобразовании одного исключения в другое?
error-handlingexceptions - 71
Как гарантировать сброс временного флага состояния, даже если операция выбросит исключение?
- 72
Как реализовать потокобезопасный счётчик запросов в Java?
concurrency - 73
Как запустить десять независимых задач с фиксированным количеством рабочих потоков?
concurrency - 74
Рабочий поток прервали во время ожидания. Как должен отреагировать его код?
concurrency - 75
Как безопасно передавать очередь между потоком-производителем и потоком-потребителем?
concurrencydata-structures - 76
Два потока обновляют общий ArrayList, и часть результатов пропадает. Как это исправить?
concurrencycollections - 77
Как избежать простого дедлока, если двум методам нужны одни и те же две блокировки?
lockingconcurrency - 78
Как сделать объект конфигурации безопасным для использования из нескольких потоков?
concurrencyconfig - 79
Как найти причину IndexOutOfBoundsException в цикле?
indexes - 80
Stream-пайплайн падает с NPE в map(String::length). Как его исправить?
ci-cdstrings - 81
Как реализовать проверку на палиндром без учёта регистра и небуквенных символов?
- 82
Как развернуть порядок слов в предложении, не меняя порядок букв внутри слов?
- 83
Как найти второе по величине различное целое число в массиве?
distinct - 84
Как определить, содержит ли массив повторяющиеся значения?
- 85
Как реализовать бинарный поиск в отсортированном массиве int?
algorithms - 86
Как проверить, являются ли две строки анаграммами?
strings - 87
Как проверить правильность парных скобок в строке?
validationstrings - 88
Как вычислить n-е число Фибоначчи без рекурсии?
recursion - 89
Массив содержит числа от 1 до n, но одно число пропущено. Как его найти?
- 90
Как циклически сдвинуть список вправо на k позиций?
- 91
Как объединить два отсортированных массива int в один отсортированный массив?
- 92
Как найти первый неповторяющийся символ в строке?
strings - 93
Как удалить дубликаты из отсортированного массива на месте?
- 94
Как найти пару чисел, сумма которых равна заданному значению?
equals-hashcode - 95
Как посчитать итоговые суммы по категориям из списка транзакций?
transactions - 96
Как реализовать метод, который делает не более трёх повторных попыток нестабильной операции?
flaky - 97
Как безопасно преобразовать Object в целое число, если вход может быть Integer или строкой с числом?
strings - 98
Как обновлять общий кеш пользовательских сессий из нескольких потоков?
concurrencycachingsessions - 99
Как отладить метод, который возвращает правильные значения, но в непредсказуемом порядке?
- 100
Как реализовать небольшой сервисный метод, который загружает заказ, проверяет владельца и помечает заказ отменённым?
ownership