200 вопросов по Java
200 вопросов по Java
Основы языка Java
Вопрос
Что такое Java?
Ответ
Java — это объектно-ориентированный язык программирования общего назначения, разработанный компанией Sun Microsystems (ныне принадлежит Oracle). Он предназначен для написания приложений, которые могут запускаться на любом устройстве с поддержкой Java Virtual Machine (JVM), без необходимости перекомпиляции.
Вопрос
Какие основные принципы лежат в основе Java?
Ответ
Основные принципы Java: простота, объектная ориентированность, платформонезависимость, безопасность, надёжность, архитектурная нейтральность, интерпретируемость, высокая производительность, многопоточность и динамичность.
Вопрос
Что такое JVM?
Ответ
JVM (Java Virtual Machine) — это виртуальная машина, которая обеспечивает выполнение байт-кода Java. Она загружает, проверяет и исполняет скомпилированный код (.class файлы), абстрагируя программу от конкретной операционной системы и аппаратного обеспечения.
Вопрос
Что такое JRE?
Ответ
JRE (Java Runtime Environment) — это среда выполнения Java, включающая JVM, стандартные библиотеки классов и другие компоненты, необходимые для запуска Java-приложений. JRE не содержит инструментов разработки, таких как компилятор.
Вопрос
Что такое JDK?
Ответ
JDK (Java Development Kit) — это набор инструментов для разработки Java-приложений. Он включает JRE, компилятор javac, отладчик, документацию и другие утилиты. JDK необходим разработчикам для создания и компиляции программ.
Вопрос
В чём разница между JDK, JRE и JVM?
Ответ
JVM — это движок выполнения байт-кода. JRE — это среда, содержащая JVM и библиотеки для запуска программ. JDK — это полный комплект разработчика, включающий JRE и инструменты сборки и отладки.
Вопрос
Что такое байт-код Java?
Ответ
Байт-код Java — это промежуточное представление исходного кода, генерируемое компилятором javac. Он сохраняется в файлах с расширением .class и исполняется JVM. Байт-код не зависит от архитектуры процессора или операционной системы.
Вопрос
Почему Java считается платформонезависимым языком?
Ответ
Java считается платформонезависимым языком, потому что скомпилированный байт-код может выполняться на любой платформе, где установлена совместимая JVM. Программа не требует повторной компиляции под каждую операционную систему.
Вопрос
Можно ли запустить Java-программу без установки JDK?
Ответ
Да, если установлена JRE. Для запуска скомпилированного .class файла или JAR-архива достаточно JRE. JDK требуется только для компиляции исходного кода.
Вопрос
Что такое точка входа в Java-программу?
Ответ
Точка входа — это статический метод main с сигнатурой:
public static void main(String[] args)
Этот метод вызывается JVM при запуске программы.
Вопрос
Почему метод main должен быть public?
Ответ
Метод main должен быть public, чтобы JVM могла получить к нему доступ извне класса при запуске программы.
Вопрос
Почему метод main должен быть static?
Ответ
Метод main должен быть static, потому что JVM вызывает его до создания каких-либо объектов программы. Статический метод принадлежит классу, а не экземпляру, и может быть вызван без создания объекта.
Вопрос
Почему метод main возвращает void?
Ответ
Метод main возвращает void, потому что он не предназначен для возврата результата вызывающей среде. Завершение программы и передача кода выхода осуществляются через System.exit(int status).
Вопрос
Можно ли перегрузить метод main?
Ответ
Да, метод main можно перегрузить, создав другие методы с именем main, но отличающимися параметрами. Однако JVM будет вызывать только стандартную версию с аргументом String[].
Пример:
public class Main {
public static void main(String[] args) {
System.out.println("Запущен основной main");
}
public static void main(int x) {
System.out.println("Перегруженный main");
}
}
При запуске выполнится только первый метод.
Вопрос
Что такое примитивные типы данных в Java?
Ответ
Примитивные типы — это встроенные типы, не являющиеся объектами. В Java их восемь:
- boolean
- byte
- short
- int
- long
- float
- double
- char
Вопрос
Каковы размеры примитивных типов в Java?
Ответ
- boolean — не определён точно, зависит от JVM
- byte — 1 байт (-128 до 127)
- short — 2 байта (-32 768 до 32 767)
- int — 4 байта (-2³¹ до 2³¹–1)
- long — 8 байт (-2⁶³ до 2⁶³–1)
- float — 4 байта (IEEE 754)
- double — 8 байт (IEEE 754)
- char — 2 байта (UTF-16, 0 до 65 535)
Вопрос
Что такое обёртки (wrapper classes)?
Ответ
Обёртки — это классы, представляющие примитивные типы как объекты. Каждому примитиву соответствует своя обёртка:
- boolean → Boolean
- byte → Byte
- short → Short
- int → Integer
- long → Long
- float → Float
- double → Double
- char → Character
Вопрос
Что такое автоупаковка и автораспаковка?
Ответ
Автоупаковка — автоматическое преобразование примитива в соответствующий объект-обёртку. Автораспаковка — обратное преобразование объекта в примитив.
Пример:
Integer x = 100; // автоупаковка
int y = x; // автораспаковка
Вопрос
Где хранятся примитивные типы и объекты в памяти?
Ответ
Примитивные типы, объявленные внутри метода, хранятся в стеке. Объекты (включая массивы и экземпляры классов) создаются в куче (heap). Ссылки на объекты хранятся в стеке или в других объектах.
Вопрос
Что такое константа в Java и как её объявить?
Ответ
Константа — это переменная, значение которой не может изменяться после инициализации. Объявляется с модификаторами final и обычно static.
Пример:
public static final double PI = 3.14159;
Вопрос
Что такое ключевое слово final?
Ответ
Ключевое слово final применяется к переменным, методам и классам:
- final-переменная не может быть переопределена после инициализации.
- final-метод не может быть переопределён в подклассе.
- final-класс не может быть унаследован.
Вопрос
Что такое var в Java?
Ответ
Ключевое слово var, введённое в Java 10, позволяет объявлять локальные переменные с выводом типа. Тип выводится из правой части выражения при инициализации.
Пример:
var name = "Java"; // тип String
var count = 42; // тип int
var нельзя использовать для полей класса, параметров методов или без инициализации.
Вопрос
Что такое комментарии в Java и какие виды существуют?
Ответ
Комментарии — это текст, игнорируемый компилятором. В Java три вида:
- Однострочные:
// комментарий - Многострочные:
/* комментарий */ - Документирующие:
/** документация */— используются для генерации JavaDoc.
Вопрос
Что такое оператор instanceof?
Ответ
Оператор instanceof проверяет, является ли объект экземпляром указанного класса или его подкласса, либо реализует ли он указанный интерфейс. Возвращает true или false.
Пример:
Object obj = "Hello";
if (obj instanceof String) {
System.out.println("Это строка");
}
Вопрос
Что такое тернарный оператор в Java?
Ответ
Тернарный оператор — это сокращённая форма условного выражения:
условие ? выражение1 : выражение2
Если условие истинно, возвращается выражение1, иначе — выражение2.
Пример:
int max = (a > b) ? a : b;
Вопрос
Какие циклы поддерживаются в Java?
Ответ
Java поддерживает три вида циклов:
- for
- while
- do-while
Также существует расширенный цикл for-each для итерации по массивам и коллекциям.
Пример for-each:
int[] numbers = {1, 2, 3};
for (int n : numbers) {
System.out.println(n);
}
Вопрос
Что делают операторы break и continue?
Ответ
Оператор break прерывает выполнение цикла или switch. Оператор continue завершает текущую итерацию цикла и переходит к следующей.
Пример:
for (int i = 0; i < 10; i++) {
if (i == 5) break; // цикл остановится на i=5
if (i % 2 == 0) continue; // пропустить чётные
System.out.println(i);
}
Вопрос
Можно ли использовать метки (labels) в Java?
Ответ
Да, Java поддерживает метки для циклов. Метка позволяет указать, какой именно цикл должен быть прерван или продолжен с помощью break или continue.
Пример:
outer:
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
if (i == 1 && j == 1) break outer;
}
}
Вопрос
Что такое блок инициализации в Java?
Ответ
Блок инициализации — это фрагмент кода в фигурных скобках внутри класса, но вне методов. Существуют два вида:
- Статический блок инициализации (с модификатором static) — выполняется один раз при загрузке класса.
- Нестатический блок — выполняется при создании каждого экземпляра класса, до конструктора.
Пример:
class Example {
static {
System.out.println("Статический блок");
}
{
System.out.println("Нестатический блок");
}
}
Вопрос
Что такое перечисления (enum) в Java?
Ответ
Перечисления — это специальный тип класса, представляющий фиксированный набор констант. Каждая константа является экземпляром enum-типа.
Пример:
enum Color { RED, GREEN, BLUE }
Color c = Color.RED;
Enum может содержать поля, методы и конструкторы.
Объектно-ориентированное программирование (ООП)
Вопрос
Что такое объектно-ориентированное программирование?
Ответ
Объектно-ориентированное программирование (ООП) — это парадигма программирования, основанная на концепции «объектов», которые являются экземплярами классов и объединяют данные (поля) и поведение (методы). ООП в Java реализует четыре основных принципа: абстракцию, инкапсуляцию, наследование и полиморфизм.
Вопрос
Что такое класс в Java?
Ответ
Класс — это шаблон или описание для создания объектов. Он определяет поля (состояние) и методы (поведение), которые будут доступны экземплярам этого класса. Класс не занимает память до тех пор, пока не создан его объект.
Пример:
class Car {
String color;
void start() {
System.out.println("Car started");
}
}
Вопрос
Что такое объект в Java?
Ответ
Объект — это экземпляр класса, созданный с помощью оператора new. У каждого объекта есть собственное состояние (значения полей) и поведение (методы, унаследованные от класса).
Пример:
Car myCar = new Car();
myCar.color = "Red";
myCar.start();
Вопрос
Что такое конструктор?
Ответ
Конструктор — это специальный метод, вызываемый при создании объекта с помощью new. Он имеет то же имя, что и класс, и не имеет возвращаемого типа. Конструктор инициализирует поля объекта.
Если конструктор не объявлен явно, компилятор создаёт конструктор по умолчанию без параметров.
Пример:
class Person {
String name;
Person(String name) {
this.name = name;
}
}
Вопрос
Можно ли перегрузить конструктор?
Ответ
Да, конструкторы можно перегружать, создавая несколько конструкторов с разными сигнатурами (разным количеством или типами параметров).
Пример:
class Box {
double width, height;
Box() { this(1.0, 1.0); } // делегирование
Box(double w) { this(w, w); }
Box(double w, double h) {
width = w;
height = h;
}
}
Вопрос
Что такое ключевое слово this?
Ответ
Ключевое слово this ссылается на текущий экземпляр класса. Оно используется для:
- обращения к полям объекта, когда их имена совпадают с параметрами метода;
- вызова другого конструктора того же класса (только в первой строке конструктора);
- передачи текущего объекта в другой метод.
Пример:
class Student {
String name;
Student(String name) {
this.name = name; // this.name — поле, name — параметр
}
}
Вопрос
Что такое инкапсуляция?
Ответ
Инкапсуляция — это механизм сокрытия внутреннего состояния объекта и предоставления доступа к нему только через публичные методы. Это достигается с помощью модификаторов доступа (private, protected, public) и геттеров/сеттеров.
Пример:
class BankAccount {
private double balance;
public double getBalance() { return balance; }
public void deposit(double amount) { balance += amount; }
}
Вопрос
Какие модификаторы доступа существуют в Java?
Ответ
В Java четыре модификатора доступа:
private— доступ только внутри класса;default(пакетный) — доступ внутри пакета;protected— доступ внутри пакета и подклассам вне пакета;public— доступ из любого места.
Вопрос
Что такое наследование?
Ответ
Наследование — это механизм, позволяющий одному классу (подклассу) унаследовать поля и методы другого класса (суперкласса). В Java наследование реализуется с помощью ключевого слова extends.
Пример:
class Animal {
void eat() { System.out.println("Eating"); }
}
class Dog extends Animal {
void bark() { System.out.println("Barking"); }
}
Вопрос
Сколько классов может наследовать Java-класс?
Ответ
Java-класс может наследовать только один класс. Множественное наследование классов в Java запрещено, чтобы избежать неоднозначностей (например, «алмазной проблемы»).
Вопрос
Что такое ключевое слово super?
Ответ
Ключевое слово super ссылается на экземпляр суперкласса. Оно используется для:
- вызова конструктора суперкласса (
super()— обязательно в первой строке); - вызова метода или доступа к полю суперкласса, если оно переопределено в подклассе.
Пример:
class Parent {
Parent() { System.out.println("Parent"); }
void greet() { System.out.println("Hello from Parent"); }
}
class Child extends Parent {
Child() {
super(); // вызов конструктора родителя
}
void greet() {
super.greet(); // вызов метода родителя
System.out.println("Hello from Child");
}
}
Вопрос
Что такое полиморфизм?
Ответ
Полиморфизм — это способность объекта принимать разные формы. В Java он реализуется через:
- переопределение методов (динамический полиморфизм);
- перегрузку методов (статический полиморфизм).
Наиболее часто под полиморфизмом понимают возможность использовать ссылку на суперкласс для работы с объектами подклассов.
Пример:
Animal a = new Dog(); // полиморфная ссылка
a.eat(); // вызов метода Dog, если он переопределён
Вопрос
Что такое переопределение метода (method overriding)?
Ответ
Переопределение метода — это создание в подклассе метода с той же сигнатурой (имя, параметры, тип возврата), что и в суперклассе. Переопределённый метод должен быть не более приватным, чем в суперклассе, и не может быть static.
JVM выбирает, какой метод вызывать, во время выполнения (динамическая диспетчеризация).
Вопрос
Что такое перегрузка метода (method overloading)?
Ответ
Перегрузка метода — это создание в одном классе нескольких методов с одним именем, но разными параметрами (по количеству, типу или порядку). Тип возврата не участвует в перегрузке.
Выбор перегруженного метода происходит на этапе компиляции (статическая диспетчеризация).
Вопрос
Можно ли переопределить статический метод?
Ответ
Нет, статические методы нельзя переопределить, потому что они принадлежат классу, а не объекту. Однако можно объявить статический метод с той же сигнатурой в подклассе — это будет сокрытие метода (method hiding), а не переопределение.
Вопрос
Что такое абстрактный класс?
Ответ
Абстрактный класс — это класс, объявленный с модификатором abstract. Он может содержать как обычные, так и абстрактные методы (без реализации). Нельзя создать экземпляр абстрактного класса напрямую — его можно только наследовать.
Пример:
abstract class Shape {
abstract double area(); // без тела
void print() { System.out.println("Shape"); } // с телом
}
Вопрос
Что такое интерфейс?
Ответ
Интерфейс — это контракт, описывающий набор методов, которые должны быть реализованы классом. До Java 8 интерфейсы содержали только абстрактные методы. Начиная с Java 8, в интерфейсах можно определять:
default-методы с реализацией;static-методы;- с Java 9 —
private-методы.
Класс реализует интерфейс с помощью ключевого слова implements.
Пример:
interface Drawable {
void draw();
default void info() {
System.out.println("Drawable object");
}
}
Вопрос
Можно ли реализовать несколько интерфейсов?
Ответ
Да, класс может реализовать сколько угодно интерфейсов. Это основной способ достижения множественного наследования поведения в Java.
Пример:
class MyClass implements Runnable, Cloneable, Serializable { ... }
Вопрос
Чем интерфейс отличается от абстрактного класса?
Ответ
Основные различия:
- Интерфейс не может иметь состояния (до Java 8 — вообще без полей; с Java 8+ — только
public static finalполя). - Все методы интерфейса по умолчанию
public. - Класс может реализовать множество интерфейсов, но наследовать только один абстрактный класс.
- Абстрактный класс может иметь конструкторы, поля, частные методы; интерфейс — нет (кроме
static finalполей иdefault/static/privateметодов).
Вопрос
Что такое маркерный интерфейс?
Ответ
Маркерный интерфейс — это интерфейс без методов, используемый для отметки класса как обладающего определённым свойством. Примеры: Serializable, Cloneable, Remote.
JVM или другие части системы проверяют наличие такой «метки» с помощью instanceof.
Вопрос
Что такое композиция и агрегация?
Ответ
Композиция и агрегация — это формы связи «часть-целое» между объектами.
- Агрегация: «имеет» — слабая связь, части могут существовать независимо от целого. Пример: университет и студенты.
- Композиция: «содержит» — сильная связь, части не могут существовать без целого. Пример: человек и сердце.
В коде обе реализуются через поля одного класса, ссылающиеся на другие.
Вопрос
Что такое пакет (package) в Java?
Ответ
Пакет — это пространство имён, группирующее связанные классы и интерфейсы. Пакеты предотвращают конфликты имён и управляют доступом (через модификатор по умолчанию).
Объявление пакета — первая строка в файле:
package com.example.utils;
Вопрос
Что такое класс Object?
Ответ
Object — это корневой класс всех классов в Java. Любой класс, явно или неявно, наследуется от Object. Он определяет общие методы, такие как:
toString()equals(Object obj)hashCode()clone()getClass()finalize()
Вопрос
Зачем переопределять метод toString()?
Ответ
Метод toString() возвращает строковое представление объекта. По умолчанию он выводит имя класса и хеш-код, что неинформативно. Переопределение позволяет вернуть осмысленное описание состояния объекта.
Пример:
@Override
public String toString() {
return "Person{name='" + name + "'}";
}
Вопрос
Зачем переопределять equals() и hashCode()?
Ответ
Методы equals() и hashCode() используются коллекциями, такими как HashMap, HashSet, для сравнения объектов и вычисления их положения в хэш-таблице.
Если два объекта равны по equals(), их hashCode() должен быть одинаковым. Нарушение этого правила приводит к ошибкам в работе коллекций.
Вопрос
Что такое контракт equals()?
Ответ
Контракт метода equals() требует, чтобы он был:
- Рефлексивным:
x.equals(x)→true; - Симметричным:
x.equals(y)↔y.equals(x); - Транзитивным: если
x.equals(y)иy.equals(z), тоx.equals(z); - Непротиворечивым: многократные вызовы возвращают один и тот же результат;
- Согласованным с null:
x.equals(null)→false.
Vopros
Что такое клонирование объектов?
Otvet
Клонирование — это создание копии объекта. В Java реализуется через интерфейс Cloneable и метод clone(), унаследованный от Object.
- Поверхностное клонирование: копируются только поля примитивных типов и ссылки на объекты.
- Глубокое клонирование: рекурсивно копируются все вложенные объекты.
Вопрос
Что такое запись (record) в Java?
Ответ
Запись (record) — это компактный способ объявления класса, предназначенного для хранения неизменяемых данных. Введена в Java 14 (preview), стабильно — с Java 16.
Компилятор автоматически генерирует:
- приватные
finalполя; - публичный конструктор;
- геттеры;
equals(),hashCode(),toString().
Пример:
record Point(int x, int y) {}
Вопрос
Можно ли наследовать запись?
Ответ
Нет, записи являются final по умолчанию и не могут быть унаследованы. Также запись не может наследовать другой класс (только Object), но может реализовывать интерфейсы.
Вопрос
Что такое sealed-классы?
Ответ
Sealed-классы (запечатанные классы) — это классы, которые могут быть расширены только определёнными подклассами, перечисленными в предложении permits. Введены в Java 17.
Пример:
sealed class Vehicle permits Car, Truck, Bike {}
final class Car extends Vehicle {}
non-sealed class Truck extends Vehicle {}
final class Bike extends Vehicle {}
Это даёт контроль над иерархией наследования.
Коллекции и работа с данными
Вопрос
Что такое фреймворк коллекций Java?
Ответ
Фреймворк коллекций Java — это набор интерфейсов и классов в пакете java.util, предназначенный для хранения и манипулирования группами объектов. Основные интерфейсы: Collection, List, Set, Queue, Deque, Map.
Вопрос
Какие основные интерфейсы есть в коллекциях?
Ответ
Основные интерфейсы:
Collection— корневой интерфейс для всех коллекций (кромеMap);List— упорядоченная коллекция с допуском дубликатов;Set— коллекция без дубликатов;Queue— коллекция для обработки по принципу «первым пришёл — первым ушёл» (FIFO);Deque— двусторонняя очередь;Map— структура «ключ-значение», не наследуетCollection.
Вопрос
В чём разница между List и Set?
Ответ
List сохраняет порядок вставки элементов и допускает дубликаты. Set не гарантирует порядок (за исключением LinkedHashSet) и не допускает дубликатов — каждый элемент уникален по equals() и hashCode().
Вопрос
Какие реализации интерфейса List существуют?
Ответ
Основные реализации List:
ArrayList— на основе динамического массива, быстрый произвольный доступ, медленная вставка/удаление в середине;LinkedList— на основе двусвязного списка, быстрая вставка/удаление, медленный доступ по индексу;Vector— устаревший, синхронизированный аналогArrayList;Stack— устаревшая реализация стека на основеVector.
Вопрос
Как устроен ArrayList внутри?
Ответ
ArrayList использует внутренний массив Object[]. При добавлении элемента, если массив заполнен, создаётся новый массив большего размера (обычно в 1.5 раза), и элементы копируются туда. Это обеспечивает амортизированную сложность O(1) для добавления в конец.
Вопрос
Является ли ArrayList потокобезопасным?
Ответ
Нет, ArrayList не является потокобезопасным. При одновременном доступе из нескольких потоков возможны повреждение данных или исключения. Для потокобезопасности можно использовать:
Collections.synchronizedList();CopyOnWriteArrayList.
Вопрос
Что такое fail-fast и fail-safe итераторы?
Ответ
- Fail-fast итераторы (например, в
ArrayList,HashMap) выбрасываютConcurrentModificationException, если коллекция была изменена во время итерации другим потоком или методом. - Fail-safe итераторы (например, в
ConcurrentHashMap,CopyOnWriteArrayList) работают с копией данных и не бросают исключение при модификации оригинальной коллекции.
Вопрос
Какие реализации интерфейса Set существуют?
Ответ
Основные реализации Set:
HashSet— на основе хэш-таблицы, неупорядоченный, быстрый доступ;LinkedHashSet— сохраняет порядок вставки;TreeSet— на основе красно-чёрного дерева, хранит элементы в отсортированном порядке (по естественному порядку или компаратору).
Вопрос
Как работает HashSet?
Ответ
HashSet использует внутреннюю HashMap, где элементы коллекции выступают в роли ключей, а значения — заглушки (PRESENT). Порядок элементов не гарантируется. Для корректной работы требуется корректная реализация hashCode() и equals() у элементов.
Вопрос
Что такое Map в Java?
Ответ
Map — это интерфейс, представляющий структуру данных «ключ-значение». Каждому ключу соответствует ровно одно значение. Ключи должны быть уникальными. Map не наследует Collection.
Вопрос
Какие основные реализации Map существуют?
Ответ
Основные реализации:
HashMap— неупорядоченный, быстрый доступ, не потокобезопасен;LinkedHashMap— сохраняет порядок вставки или порядок доступа;TreeMap— хранит пары в отсортированном порядке по ключам;Hashtable— устаревшая, синхронизированная реализация;ConcurrentHashMap— потокобезопасная, высокопроизводительная реализация.
Вопрос
Как устроен HashMap внутри?
Ответ
HashMap хранит данные в виде массива «корзин» (buckets). Каждая корзина содержит связный список или дерево (начиная с Java 8, если в корзине более 8 элементов и размер таблицы ≥ 64). Хэш-код ключа определяет индекс корзины. Коллизии разрешаются через списки/деревья.
Вопрос
Почему ключи в HashMap должны быть неизменяемыми?
Ответ
Если ключ изменится после вставки в HashMap, его хэш-код может измениться, и при попытке получить значение по тому же объекту оно не будет найдено, потому что поиск происходит в другой корзине. Поэтому ключи должны быть неизменяемыми или хотя бы не менять поля, участвующие в hashCode() и equals().
Вопрос
Что такое load factor в HashMap?
Ответ
Load factor (коэффициент загрузки) — это порог, при достижении которого HashMap увеличивает свою ёмкость. По умолчанию он равен 0.75. Например, при начальной ёмкости 16 таблица будет расширена при вставке 13-го элемента (16 × 0.75 = 12).
Вопрос
Как обрабатывает коллизии HashMap?
Ответ
Коллизии возникают, когда разные ключи дают одинаковый хэш-индекс. До Java 8 они хранились в виде связного списка. Начиная с Java 8, если в одной корзине накапливается более 8 элементов и общая ёмкость ≥ 64, список преобразуется в сбалансированное дерево (красно-чёрное), чтобы ускорить поиск с O(n) до O(log n).
Вопрос
В чём разница между HashMap и Hashtable?
Ответ
HashMapне синхронизирован,Hashtable— синхронизирован;HashMapдопускаетnullв качестве ключа и значения,Hashtable— нет;HashMapбыстрее в однопоточной среде;Hashtableсчитается устаревшим.
Вопрос
Что такое ConcurrentHashMap?
Ответ
ConcurrentHashMap — это потокобезопасная реализация Map, обеспечивающая высокую производительность за счёт сегментирования (в Java 7) или CAS-операций и блокировок на уровне корзин (в Java 8+). Она не блокирует всю таблицу при операциях чтения и частично при записи.
Вопрос
Можно ли использовать null в ConcurrentHashMap?
Ответ
Нет, ConcurrentHashMap не допускает null ни в качестве ключа, ни в качестве значения. Это сделано для избежания неоднозначности при возврате null: невозможно определить, отсутствует ли ключ или значение действительно null.
Вопрос
Что такое Comparable и Comparator?
Ответ
Comparable— интерфейс, который реализуется классом для определения естественного порядка сортировки через методcompareTo().Comparator— внешний интерфейс для определения альтернативного порядка сортировки через методcompare().
Пример:
class Person implements Comparable<Person> {
public int compareTo(Person other) { ... }
}
Comparator<Person> byAge = (p1, p2) -> Integer.compare(p1.age, p2.age);
Вопрос
Как отсортировать список объектов?
Ответ
Список можно отсортировать с помощью:
Collections.sort(list)— если элементы реализуютComparable;Collections.sort(list, comparator)— с использованием внешнегоComparator;list.sort(comparator)— метод по умолчанию вList.
Вопрос
Что такое PriorityQueue?
Ответ
PriorityQueue — это очередь, в которой элементы извлекаются в порядке их приоритета (наименьший элемент — первый). По умолчанию используется естественный порядок, либо заданный Comparator. Внутренне реализована как двоичная куча.
Вопрос
Поддерживает ли PriorityQueue null?
Ответ
Нет, PriorityQueue не допускает null, потому что не может определить его приоритет относительно других элементов.
Вопрос
Что такое Deque?
Ответ
Deque (double-ended queue) — это очередь, поддерживающая вставку и удаление с обоих концов. Может использоваться как стек (LIFO) или как очередь (FIFO). Реализации: ArrayDeque, LinkedList.
Вопрос
В чём преимущество ArrayDeque перед Stack?
Ответ
ArrayDeque быстрее, чем устаревший Stack, не синхронизирован и не наследует Vector. Он рекомендован как основная реализация стека в современном Java.
Вопрос
Что такое UnsupportedOperationException?
Ответ
Это исключение выбрасывается, когда вызывается метод, не поддерживаемый конкретной реализацией коллекции. Например, Arrays.asList() возвращает фиксированный по размеру список, и вызов add() на нём приведёт к этому исключению.
Вопрос
Как создать неизменяемую коллекцию?
Ответ
Начиная с Java 9, можно использовать фабричные методы:
List<String> list = List.of("a", "b", "c");
Set<Integer> set = Set.of(1, 2, 3);
Map<String, Integer> map = Map.of("key", 42);
Такие коллекции неизменяемы: любая попытка модификации вызовет UnsupportedOperationException.
Вопрос
Что такое Iterable и Iterator?
Ответ
Iterable— интерфейс, позволяющий объекту быть целью цикла for-each. Содержит методiterator().Iterator— интерфейс для последовательного обхода коллекции с возможностью безопасного удаления элементов черезremove().
Вопрос
Можно ли модифицировать коллекцию во время итерации?
Ответ
Напрямую — нельзя. Любая модификация коллекции (кроме вызова Iterator.remove()) во время итерации приведёт к ConcurrentModificationException у fail-fast итераторов. Для безопасной модификации следует использовать итератор или копию коллекции.
Вопрос
Что такое Spliterator?
Ответ
Spliterator — это специальный итератор, поддерживающий параллельное и последовательное разбиение источника данных. Используется в Stream API для эффективной обработки больших коллекций.
Исключения и обработка ошибок
Вопрос
Что такое исключение в Java?
Ответ
Исключение — это событие, нарушающее нормальный поток выполнения программы. В Java все исключения представлены объектами, унаследованными от класса Throwable.
Вопрос
Какова иерархия исключений в Java?
Ответ
Корень иерархии — класс Throwable. Он имеет два основных подкласса:
Error— указывает на серьёзные проблемы, которые не следует обрабатывать (например,OutOfMemoryError);Exception— представляет условия, которые можно и нужно обрабатывать.
Exception делится на:
- Проверяемые (checked) — должны быть либо перехвачены, либо объявлены в
throws; - Непроверяемые (unchecked) — наследники
RuntimeException, не требуют обязательной обработки.
Вопрос
Что такое проверяемое исключение?
Ответ
Проверяемое исключение — это подкласс Exception, но не RuntimeException. Компилятор требует, чтобы такой код был либо обёрнут в try-catch, либо метод объявлял его через throws.
Пример: IOException, SQLException.
Вопрос
Что такое непроверяемое исключение?
Ответ
Непроверяемое исключение — это подкласс RuntimeException. Компилятор не требует его явной обработки. Такие исключения обычно возникают из-за ошибок программиста.
Пример: NullPointerException, ArrayIndexOutOfBoundsException, IllegalArgumentException.
Вопрос
Можно ли создать собственное исключение?
Ответ
Да. Для этого нужно создать класс, унаследованный от Exception (для проверяемого) или от RuntimeException (для непроверяемого).
Пример:
class InvalidAgeException extends Exception {
public InvalidAgeException(String message) {
super(message);
}
}
Вопрос
Что делает блок try-catch?
Ответ
Блок try содержит код, который может выбросить исключение. Блок catch перехватывает и обрабатывает исключение указанного типа. Можно использовать несколько catch-блоков для разных типов исключений.
Пример:
try {
int result = 10 / 0;
} catch (ArithmeticException e) {
System.out.println("Деление на ноль");
}
Вопрос
Что такое блок finally?
Ответ
Блок finally выполняется всегда — независимо от того, было ли выброшено исключение, перехвачено оно или нет. Используется для освобождения ресурсов (закрытие файлов, соединений и т.п.).
Единственное исключение — вызов System.exit() или аварийное завершение JVM.
Vopros
Что такое try-with-resources?
Otvet
try-with-resources — это конструкция, автоматически закрывающая ресурсы, реализующие интерфейс AutoCloseable (включая Closeable). Ресурсы объявляются в скобках после try и закрываются в неявном finally.
Пример:
try (FileInputStream fis = new FileInputStream("file.txt")) {
// работа с файлом
} // fis.close() вызывается автоматически
Вопрос
Какие требования к ресурсу в try-with-resources?
Ответ
Ресурс должен реализовывать интерфейс AutoCloseable. Это гарантирует наличие метода close(), который будет вызван при выходе из блока.
Вопрос
Можно ли использовать несколько ресурсов в try-with-resources?
Ответ
Да. Несколько ресурсов перечисляются через точку с запятой. Они закрываются в порядке, обратном их объявлению.
Пример:
try (FileInputStream fis = new FileInputStream("in.txt");
FileOutputStream fos = new FileOutputStream("out.txt")) {
// обработка
}
Вопрос
Что происходит, если исключение возникает и в try, и в close()?
Ответ
Исключение из блока try считается основным. Исключение из close() подавляется (suppressed) и может быть получено через метод getSuppressed() у основного исключения.
Вопрос
Что делает ключевое слово throw?
Ответ
Ключевое слово throw используется для явного выброса исключения.
Пример:
if (age < 0) {
throw new IllegalArgumentException("Возраст не может быть отрицательным");
}
Вопрос
Что делает ключевое слово throws?
Ответ
Ключевое слово throws указывается в сигнатуре метода и объявляет, что метод может выбросить одно или несколько проверяемых исключений. Это передаёт ответственность за обработку вызывающему коду.
Пример:
public void readFile() throws IOException {
// может выбросить IOException
}
Вопрос
Можно ли перехватить Throwable?
Ответ
Технически — да, но это не рекомендуется. Перехват Error или Throwable может скрыть критические сбои JVM (например, OutOfMemoryError), что затрудняет диагностику и восстановление.
Вопрос
Что такое многократный catch (multi-catch)?
Ответ
Начиная с Java 7, можно перехватывать несколько типов исключений в одном catch-блоке, разделяя их вертикальной чертой |. Объект исключения внутри блока является финальным.
Пример:
catch (IOException | SQLException e) {
logger.error("Ошибка: " + e.getMessage());
}
Вопрос
Можно ли повторно выбросить исключение?
Ответ
Да. Это называется re-throw. Используется, когда нужно частично обработать исключение, но передать его выше по стеку вызовов.
Пример:
catch (IOException e) {
log(e);
throw e; // сохраняет оригинальный стек
}
Вопрос
Что такое «потерянное исключение»?
Ответ
«Потерянное исключение» возникает, когда новое исключение выбрасывается в блоке finally, перекрывая исключение из try. Это скрывает первоначальную ошибку. Использование try-with-resources помогает избежать этой проблемы.
Вопрос
Нужно ли всегда обрабатывать исключения?
Ответ
Нет. Иногда лучше позволить исключению подняться выше, особенно если текущий уровень не может адекватно на него реагировать. Однако на верхнем уровне (например, в main или контроллере) исключения должны быть обработаны, чтобы программа не завершилась аварийно.
Вопрос
Что такое «голое» исключение (bare exception)?
Ответ
«Голое» исключение — это перехват исключения без какой-либо обработки (пустой catch-блок). Это плохая практика, так как скрывает ошибку и затрудняет отладку.
Пример плохого кода:
try { ... } catch (Exception e) {} // никогда так не делать
Вопрос
Как логировать исключения правильно?
Ответ
Следует логировать исключение с полным стеком вызовов, используя методы вроде logger.error("Сообщение", e). Не следует выводить только e.getMessage(), так как это теряет контекст ошибки.
Вопрос
Можно ли выбросить исключение из блока finally?
Ответ
Можно, но это крайне нежелательно. Исключение из finally подавит любое исключение, выброшенное в try или catch, что приведёт к потере информации об ошибке.
Вопрос
Что такое исключение времени компиляции и времени выполнения?
Ответ
- Исключения времени компиляции — это синтаксические или семантические ошибки, обнаруживаемые компилятором (например, необработанное проверяемое исключение).
- Исключения времени выполнения — это ошибки, возникающие во время исполнения программы (например,
NullPointerException).
Вопрос
Влияют ли исключения на производительность?
Ответ
Создание и выброс исключения требует сбора стека вызовов, что относительно дорого. Поэтому исключения не следует использовать для управления логикой программы (например, вместо условий). Их нужно применять только для обработки действительно исключительных ситуаций.
Вопрос
Что такое «цепочка исключений» (chained exceptions)?
Ответ
Цепочка исключений — это механизм, позволяющий сохранить причину (cause) одного исключения внутри другого. Это достигается передачей исходного исключения в конструктор нового.
Пример:
try {
// ...
} catch (IOException e) {
throw new ServiceException("Не удалось обработать запрос", e);
}
Вопрос
Как получить первопричину исключения?
Ответ
Метод getCause() возвращает исключение, которое стало причиной текущего. Можно рекурсивно вызывать getCause(), пока не получим null.
Вопрос
Можно ли выбросить проверяемое исключение без объявления throws?
Ответ
Технически — да, с помощью хаков (например, через обобщения или Unsafe), но это нарушает контракт языка и считается плохой практикой. Компилятор и JVM рассчитывают на соблюдение правил проверяемых исключений.
Вопрос
Что такое StackOverflowError?
Ответ
StackOverflowError — это подкласс Error, возникающий при переполнении стека вызовов, обычно из-за бесконечной рекурсии.
Вопрос
Что такое OutOfMemoryError?
Ответ
OutOfMemoryError — это подкласс Error, возникающий, когда JVM не может выделить память для нового объекта, потому что куча исчерпана и сборка мусора не освободила достаточно места.
Вопрос
Чем Error отличается от Exception?
Ответ
Error указывает на серьёзные системные проблемы, которые приложение обычно не может обработать (например, сбой JVM). Exception представляет условия, которые могут быть предвидены и обработаны программистом.
Многопоточность и параллелизм
Вопрос
Что такое поток (thread) в Java?
Ответ
Поток — это независимый путь выполнения внутри процесса. В Java каждый запущенный метод main выполняется в главном потоке (main thread). Дополнительные потоки создаются либо наследованием класса Thread, либо реализацией интерфейса Runnable.
Вопрос
Как создать поток в Java?
Ответ
Существует два основных способа:
- Реализовать интерфейс
Runnableи передать экземпляр в конструкторThread:Thread t = new Thread(() -> System.out.println("Hello"));
t.start(); - Наследовать класс
Threadи переопределить методrun()(реже используется).
Рекомендуется использовать Runnable, так как Java не поддерживает множественное наследование классов.
Вопрос
В чём разница между процессом и потоком?
Ответ
- Процесс — это отдельная исполняемая программа со своим адресным пространством.
- Поток — это лёгковесный компонент внутри процесса, разделяющий с другими потоками память и ресурсы процесса.
Потоки одного процесса могут взаимодействовать напрямую; процессы — только через IPC (межпроцессное взаимодействие).
Вопрос
Какие состояния есть у потока в Java?
Ответ
Поток может находиться в одном из следующих состояний (перечисление Thread.State):
NEW— создан, но ещё не запущен;RUNNABLE— готов к выполнению или выполняется;BLOCKED— ожидает монитор (например, при входе вsynchronized);WAITING— ожидает без тайм-аута (например,wait(),join());TIMED_WAITING— ожидает с тайм-аутом (например,sleep(),wait(1000));TERMINATED— завершил выполнение.
Вопрос
Что делает метод start()?
Ответ
Метод start() регистрирует поток в JVM и планирует его выполнение. Он вызывает метод run() в новом потоке. Вызов run() напрямую выполняет код в текущем потоке — это не создаёт новый поток.
Вопрос
Что такое гонка данных (race condition)?
Ответ
Гонка данных — это ситуация, когда поведение программы зависит от порядка выполнения потоков, и результат становится непредсказуемым. Возникает при одновременном доступе нескольких потоков к общему изменяемому состоянию без синхронизации.
Вопрос
Как предотвратить гонку данных?
Ответ
Гонку данных предотвращают с помощью синхронизации доступа к общим ресурсам. Основные механизмы:
- ключевое слово
synchronized; - классы из пакета
java.util.concurrent.locks(например,ReentrantLock); - атомарные переменные (
AtomicInteger,AtomicReference); - неизменяемые объекты.
Вопрос
Что такое ключевое слово synchronized?
Ответ
synchronized обеспечивает взаимное исключение: только один поток может выполнять синхронизированный блок или метод в один момент времени. Он использует монитор (встроенный объектный замок).
Пример:
public synchronized void increment() {
count++;
}
Эквивалентно:
public void increment() {
synchronized(this) {
count++;
}
}
Вопрос
Что такое монитор в Java?
Ответ
Монитор — это механизм синхронизации, связанный с каждым объектом в Java. Поток должен получить монитор объекта, чтобы войти в synchronized-блок или метод. Если монитор занят другим потоком, текущий поток переходит в состояние BLOCKED.
Вопрос
Можно ли синхронизировать статический метод?
Ответ
Да. Синхронизация статического метода блокирует классовый объект (MyClass.class), а не экземпляр. Это означает, что только один поток во всём приложении может выполнять этот метод в данный момент.
Вопрос
Что такое взаимная блокировка (deadlock)?
Ответ
Взаимная блокировка — это ситуация, когда два или более потоков бесконечно ждут освобождения ресурсов, удерживаемых друг другом. Например:
- Поток A держит замок X и ждёт Y;
- Поток B держит замок Y и ждёт X.
Оба потока блокируются навсегда.
Вопрос
Как избежать deadlock?
Ответ
Основные стратегии:
- Захватывать замки в одинаковом порядке во всех потоках;
- Использовать тайм-ауты при попытке захвата (
tryLock()с тайм-аутом); - Избегать вложенных блокировок;
- Использовать высокоуровневые конструкции (
java.util.concurrent).
Вопрос
Что такое volatile?
Ответ
Ключевое слово volatile гарантирует:
- Видимость: изменения переменной одним потоком сразу становятся видны другим;
- Запрет перестановки: компилятор и процессор не могут переупорядочивать операции с
volatile-переменной относительно других операций.
Однако volatile не обеспечивает атомарности составных операций (например, i++).
Вопрос
Чем volatile отличается от synchronized?
Ответ
volatileприменяется к отдельным переменным и не блокирует потоки;synchronizedблокирует целые участки кода и обеспечивает атомарность;volatileне подходит для операций чтение-модификация-запись, если они не атомарны.
Вопрос
Что такое атомарные переменные?
Ответ
Атомарные переменные — это классы из пакета java.util.concurrent.atomic (например, AtomicInteger, AtomicLong, AtomicReference), которые обеспечивают атомарные операции без блокировок, используя CAS (Compare-And-Swap) на уровне процессора.
Пример:
AtomicInteger counter = new AtomicInteger(0);
counter.incrementAndGet(); // атомарно увеличивает на 1
Вопрос
Что такое CAS (Compare-And-Swap)?
Ответ
CAS — это атомарная операция на уровне процессора, которая сравнивает значение переменной с ожидаемым и, если они равны, заменяет его новым значением. Используется в неблокирующих алгоритмах.
Вопрос
Что такое Executor и ExecutorService?
Ответ
Executor— простой интерфейс с методомexecute(Runnable);ExecutorService— расширениеExecutor, добавляющее управление жизненным циклом, возможность отправки задач с возвратом результата (submit()), завершения работы и полученияFuture.
Вопрос
Как создать пул потоков?
Ответ
Используется фабричный класс Executors:
newFixedThreadPool(n)— фиксированное число потоков;newCachedThreadPool()— динамически растущий пул;newSingleThreadExecutor()— один поток;newScheduledThreadPool(n)— для задач с задержкой или периодичностью.
Пример:
ExecutorService executor = Executors.newFixedThreadPool(4);
executor.submit(() -> System.out.println("Task"));
Вопрос
Что такое Future?
Ответ
Future — это объект, представляющий результат асинхронной операции. Он позволяет:
- проверить, завершена ли задача (
isDone()); - отменить задачу (
cancel()); - получить результат (
get()), блокируя поток до завершения.
Вопрос
Что такое CompletableFuture?
Ответ
CompletableFuture — это расширение Future, поддерживающее функциональный стиль, композицию и обработку результатов без блокировки. Позволяет строить цепочки асинхронных операций с обработкой успеха и ошибок.
Пример:
CompletableFuture.supplyAsync(() -> fetchData())
.thenApply(data -> process(data))
.thenAccept(result -> System.out.println(result));
Вопрос
Что такое ForkJoinPool?
Ответ
ForkJoinPool — это пул потоков, оптимизированный для выполнения задач, которые можно рекурсивно разбить на подзадачи («разделяй и властвуй»). Использует work-stealing — потоки «крадут» задачи у других, если их очередь пуста.
Используется в Stream API для параллельных операций.
Вопрос
Что такое параллельный Stream?
Ответ
Параллельный Stream — это поток данных, обрабатываемый одновременно несколькими потоками из ForkJoinPool.commonPool(). Создаётся вызовом .parallelStream() или .parallel().
Пример:
list.parallelStream().map(x -> x * 2).forEach(System.out::println);
Требует осторожности: операции должны быть без побочных эффектов и ассоциативными.
Вопрос
Что такое happens-before?
Ответ
Happens-before — это отношение в модели памяти Java, определяющее, когда изменения одного потока становятся видны другому. Например:
- Запись в
volatileпеременную happens-before чтения этой переменной; - Выход из
synchronizedблока happens-before входа другого потока в тот же блок.
Вопрос
Что такое ThreadLocal?
Ответ
ThreadLocal предоставляет отдельную копию переменной для каждого потока. Полезно для хранения контекста (например, ID пользователя, транзакции), который не должен разделяться между потоками.
Пример:
private static ThreadLocal<SimpleDateFormat> formatter =
ThreadLocal.withInitial(() -> new SimpleDateFormat("yyyy-MM-dd"));
Вопрос
Можно ли остановить поток принудительно?
Ответ
Методы stop(), suspend(), resume() устарели и опасны. Корректный способ — использовать флаг или interrupt().
Пример корректного завершения:
volatile boolean running = true;
while (running) { /* работа */ }
// или
while (!Thread.currentThread().isInterrupted()) { /* работа */ }
Вопрос
Что делает метод interrupt()?
Ответ
Метод interrupt() устанавливает флаг прерывания потока. Если поток находится в состоянии WAITING или TIMED_WAITING (например, в sleep()), он выбрасывает InterruptedException и сбрасывает флаг. В других случаях поток должен самостоятельно проверять флаг через isInterrupted().
Вопрос
Что такое daemon-потоки?
Ответ
Daemon-потоки — это фоновые потоки, которые не препятствуют завершению JVM. Когда все пользовательские (не-daemon) потоки завершаются, JVM завершает работу, даже если daemon-потоки ещё активны.
Устанавливаются через thread.setDaemon(true) до вызова start().
Вопрос
Что такое CountDownLatch?
Ответ
CountDownLatch — это синхронизатор, позволяющий одному или нескольким потокам ждать, пока другие потоки не завершат определённое количество операций. Счётчик уменьшается вызовом countDown(), ожидание — вызовом await().
Вопрос
Что такое CyclicBarrier?
Ответ
CyclicBarrier — это синхронизатор, заставляющий набор потоков ждать, пока все они не достигнут определённой точки (барьера). После этого все потоки продолжают выполнение. Барьер можно повторно использовать (в отличие от CountDownLatch).
Вопрос
Что такое Semaphore?
Ответ
Semaphore — это счётчик разрешений, ограничивающий количество потоков, которые могут одновременно получить доступ к ресурсу. Метод acquire() запрашивает разрешение, release() — возвращает его.
JVM, сборка мусора и производительность
Вопрос
Что такое JVM?
Ответ
JVM (Java Virtual Machine) — это виртуальная машина, обеспечивающая выполнение байт-кода Java. Она загружает классы, проверяет их корректность, управляет памятью, выполняет сборку мусора и оптимизирует код во время выполнения.
Вопрос
Какие области памяти есть в JVM?
Ответ
Основные области памяти JVM:
- Методная область (Metaspace) — хранит метаданные классов (до Java 8 использовалась PermGen);
- Куча (Heap) — хранит объекты и массивы;
- Стек потока (Stack) — хранит фреймы методов, локальные переменные и частичные результаты;
- Регистр PC (Program Counter) — указывает на текущую выполняемую инструкцию;
- Native Method Stack — используется для нативных методов (JNI).
Вопрос
Что такое куча (heap) в JVM?
Ответ
Куча — это область памяти, общая для всех потоков, где создаются все объекты и массивы. Она делится на поколения: Young Generation (Eden, Survivor S0/S1) и Old Generation (Tenured). Сборка мусора работает преимущественно с кучей.
Вопрос
Что такое стек (stack) в JVM?
Ответ
Стек — это область памяти, выделяемая каждому потоку отдельно. Он содержит фреймы (стековые кадры), каждый из которых соответствует вызову метода и хранит локальные переменные, параметры и ссылку на исключение. Стек удаляется при завершении потока.
Вопрос
В чём разница между стеком и кучей?
Ответ
- Стек: быстрый доступ, автоматическое управление памятью (пуш/поп при вызове/возврате из метода), привязан к потоку, хранит примитивы и ссылки на объекты.
- Куча: медленнее, требует сборки мусора, общая для всех потоков, хранит сами объекты.
Вопрос
Что такое сборка мусора (Garbage Collection, GC)?
Ответ
Сборка мусора — это автоматический процесс освобождения памяти от объектов, на которые больше нет активных ссылок. JVM периодически запускает GC, чтобы предотвратить утечки памяти и обеспечить эффективное использование ресурсов.
Вопрос
Как определяется «достижимость» объекта?
Ответ
Объект считается достижимым, если на него можно добраться от корневых ссылок (GC roots):
- локальные переменные активных потоков;
- статические поля;
- JNI-ссылки;
- активные синхронизированные мониторы.
Если цепочка ссылок от GC root до объекта отсутствует, он считается мусором.
Вопрос
Какие поколения объектов есть в куче?
Ответ
Куча делится на:
- Young Generation — новые объекты. Состоит из:
- Eden — место рождения объектов;
- Survivor spaces (S0, S1) — выжившие после минорных GC.
- Old Generation (Tenured) — долго живущие объекты, пережившие несколько сборок в Young.
- Metaspace — не часть кучи, хранит метаданные классов.
Вопрос
Что такое Minor GC и Major GC?
Ответ
- Minor GC — сборка мусора в Young Generation. Происходит часто, быстро.
- Major GC (Full GC) — сборка в Old Generation и Metaspace. Занимает значительно больше времени и останавливает все потоки приложения (stop-the-world).
Вопрос
Какие алгоритмы сборки мусора существуют в JVM?
Ответ
Основные сборщики:
- Serial GC — однопоточный, подходит для маленьких приложений;
- Parallel GC — многопоточный, ориентирован на пропускную способность;
- CMS (Concurrent Mark-Sweep) — устаревший, стремился минимизировать паузы;
- G1 (Garbage-First) — современный, балансирует между пропускной способностью и задержками;
- ZGC и Shenandoah — низкоприоритетные сборщики с паузами < 10 мс, доступны с Java 11+.
Вопрос
Что такое stop-the-world?
Ответ
Stop-the-world — это пауза в работе приложения, во время которой все потоки приостанавливаются, чтобы сборщик мусора мог безопасно анализировать и освобождать память. Все GC вызывают такие паузы, но их длительность зависит от алгоритма.
Вопрос
Как выбрать сборщик мусора?
Ответ
Выбор зависит от требований:
- Для приложений с большим объёмом данных и допустимыми паузами — Parallel GC;
- Для интерактивных систем с жёсткими требованиями к задержкам — G1, ZGC или Shenandoah;
- Для маленьких приложений — Serial GC.
Вопрос
Что такое OutOfMemoryError: Java heap space?
Ответ
Эта ошибка возникает, когда JVM не может выделить память для нового объекта в куче, потому что она заполнена, и сборка мусора не смогла освободить достаточно места. Решение — увеличить размер кучи (-Xmx) или оптимизировать использование памяти.
Вопрос
Что такое OutOfMemoryError: Metaspace?
Ответ
Возникает, когда исчерпан лимит памяти для метаданных классов (Metaspace). По умолчанию ограничен только объёмом нативной памяти, но можно задать явный лимит через -XX:MaxMetaspaceSize. Часто вызвано динамической генерацией большого числа классов (например, в Spring, Hibernate, Groovy).
Вопрос
Как профилировать память Java-приложения?
Ответ
Используются инструменты:
- jstat — мониторинг GC в реальном времени;
- jmap — дамп кучи;
- jconsole, VisualVM, JProfiler, YourKit — графические профайлеры;
- Eclipse MAT — анализ дампов кучи для поиска утечек.
Вопрос
Что такое утечка памяти в Java?
Ответ
Утечка памяти — это ситуация, когда объекты больше не нужны приложению, но остаются достижимыми (например, из-за статических коллекций, слушателей, кэшей без ограничений), поэтому GC не может их удалить. Со временем это приводит к OutOfMemoryError.
Вопрос
Как избежать утечек памяти?
Ответ
Рекомендации:
- Очищать коллекции и кэши;
- Удалять слушателей и callback’и;
- Использовать слабые ссылки (
WeakHashMap,WeakReference); - Избегать долгоживущих статических ссылок на объекты;
- Проверять жизненный цикл объектов в DI-контейнерах.
Вопрос
Что такое JIT-компилятор?
Ответ
JIT (Just-In-Time) компилятор — это компонент JVM, который преобразует часто выполняемый байт-код в нативный машинный код во время выполнения. Это повышает производительность за счёт оптимизаций, таких как инлайнинг, элиминация мёртвого кода и оптимизация циклов.
Вопрос
Как работает JIT?
Ответ
JIT отслеживает «горячие» методы (часто вызываемые). После определённого порога вызовов метод компилируется в нативный код и кэшируется. Последующие вызовы используют скомпилированную версию, а не интерпретируемый байт-код.
Вопрос
Что такое escape analysis?
Ответ
Escape analysis — это оптимизация JIT, определяющая, «выходит ли» объект за пределы метода или потока. Если объект не экранирует, JVM может:
- аллоцировать его в стеке вместо кучи;
- устранить синхронизацию (
synchronized), если объект используется только в одном потоке.
Вопрос
Что такое инлайнинг?
Ответ
Инлайнинг — это оптимизация, при которой тело вызываемого метода вставляется непосредственно в точку вызова, устраняя накладные расходы на вызов. Особенно эффективен для маленьких методов (например, геттеров).
Вопрос
Как измерить производительность Java-кода?
Ответ
Для измерения производительности следует:
- Использовать JMH (Java Microbenchmark Harness) — официальный фреймворк от OpenJDK;
- Прогревать JIT перед замерами;
- Избегать
System.currentTimeMillis()— использоватьSystem.nanoTime(); - Запускать тесты многократно и усреднять результаты.
Вопрос
Почему System.gc() не рекомендуется?
Ответ
Вызов System.gc() — это лишь подсказка JVM, которая может быть проигнорирована. Даже если вызов сработает, он может спровоцировать Full GC с длительной паузой, ухудшая производительность. Управление GC лучше оставить на усмотрение JVM.
Вопрос
Что такое TLAB (Thread Local Allocation Buffer)?
Ответ
TLAB — это небольшой буфер в куче, выделяемый каждому потоку для быстрой аллокации объектов без конкуренции. Большинство объектов создаются в TLAB, что снижает нагрузку на синхронизацию при выделении памяти.
Вопрос
Как влияет размер кучи на производительность?
Ответ
Слишком маленькая куча вызывает частые GC и снижает пропускную способность. Слишком большая — увеличивает длительность Full GC и потребление памяти. Оптимальный размер подбирается экспериментально, исходя из рабочей нагрузки.
Вопрос
Что такое компактификация памяти?
Ответ
Компактификация — это процесс перемещения «живых» объектов в смежные области памяти после сборки мусора, чтобы устранить фрагментацию. Это позволяет эффективно выделять память под новые объекты. Не все сборщики её выполняют (например, G1 делает частичную компактификацию).
Вопрос
Что такое карта пометок (mark bitmap)?
Ответ
Карта пометок — это структура данных, используемая GC для отслеживания, какие объекты являются живыми. Во время фазы mark каждый достижимый объект помечается в этой карте. Затем мусор (непомеченные объекты) удаляется.
Вопрос
Можно ли отключить сборку мусора?
Ответ
Нет, сборка мусора является неотъемлемой частью JVM. Однако можно выбрать сборщик с минимальными паузами (например, ZGC) или управлять его поведением через параметры (-XX:+DisableExplicitGC, -XX:MaxGCPauseMillis и т.д.).
Продвинутые темы и лучшие практики
Вопрос
Что такое лямбда-выражения в Java?
Ответ
Лямбда-выражения — это краткий синтаксис для представления анонимных функций (экземпляров функциональных интерфейсов). Введены в Java 8.
Пример:
Runnable r = () -> System.out.println("Hello");
Comparator<Integer> cmp = (a, b) -> Integer.compare(a, b);
Вопрос
Что такое функциональный интерфейс?
Ответ
Функциональный интерфейс — это интерфейс с ровно одним абстрактным методом. Может иметь default и static методы. Аннотация @FunctionalInterface не обязательна, но рекомендуется для проверки компилятором.
Примеры: Runnable, Callable, Predicate, Function, Consumer, Supplier.
Вопрос
Что такое ссылка на метод (method reference)?
Ответ
Ссылка на метод — это компактная альтернатива лямбде, когда метод уже существует. Обозначается как ::.
Примеры:
// Статический метод
Function<String, Integer> f = Integer::parseInt;
// Метод экземпляра
String::length
// Конструктор
Supplier<List<String>> s = ArrayList::new;
Вопрос
Что такое Stream API?
Ответ
Stream API — это фреймворк для декларативной обработки последовательностей элементов (коллекций, массивов и т.д.). Поддерживает операции:
- промежуточные (
filter,map,sorted); - терминальные (
collect,forEach,reduce).
Потоки не хранят данные и не изменяют источник.
Вопрос
В чём разница между Collection и Stream?
Ответ
- Collection — структура данных, хранящая элементы; ориентирована на доступ и управление памятью.
- Stream — вычислительный конвейер над данными; ориентирован на обработку и трансформацию.
Коллекция можно обойти многократно; поток — только один раз.
Вопрос
Что такое Optional?
Ответ
Optional<T> — это контейнерный класс, предназначенный для предотвращения NullPointerException. Он может содержать значение или быть пустым.
Пример:
Optional<String> opt = Optional.ofNullable(getName());
opt.ifPresent(name -> System.out.println(name));
String result = opt.orElse("Default");
Вопрос
Какие новые возможности появились в Java после версии 8?
Ответ
Ключевые нововведения:
- Java 9: модульная система (JPMS),
List.of(),ProcessHandle; - Java 10:
varдля локальных переменных; - Java 11: HTTP Client (стандартный),
String.isBlank(),Files.readString(); - Java 14: записи (
record); - Java 15: текстовые блоки (
"""..."""); - Java 17 (LTS): sealed-классы, удаление апплетов;
- Java 21 (LTS): виртуальные потоки, шаблоны строк, последовательные коллекции.
Вопрос
Что такое модульная система (JPMS)?
Ответ
JPMS (Java Platform Module System), введённая в Java 9, позволяет организовывать код в модули с явными зависимостями и инкапсуляцией пакетов. Модуль описывается файлом module-info.java.
Пример:
module com.example.app {
requires java.sql;
exports com.example.api;
}
Вопрос
Что такое рефлексия в Java?
Ответ
Рефлексия — это механизм, позволяющий исследовать и манипулировать классами, методами, полями и конструкторами во время выполнения. Основные классы: Class, Method, Field, Constructor.
Используется в фреймворках (Spring, Hibernate), сериализации, тестировании.
Вопрос
Как получить объект Class?
Ответ
Три способа:
Class<String> c1 = String.class; // через литерал
Class<?> c2 = obj.getClass(); // через экземпляр
Class<?> c3 = Class.forName("java.lang.String"); // по имени
Вопрос
Что такое аннотации?
Ответ
Аннотации — это метаданные, которые можно применять к классам, методам, полям и другим элементам кода. Они не влияют на логику программы напрямую, но используются компилятором, библиотеками или средой выполнения.
Примеры: @Override, @Deprecated, @FunctionalInterface, @Test.
Вопрос
Можно ли создать собственную аннотацию?
Ответ
Да. Синтаксис похож на интерфейс, с ключевым словом @interface.
Пример:
@interface Author {
String name();
int version() default 1;
}
@Author(name = "John")
class MyClass { }
Вопрос
Что такое retention policy аннотации?
Ответ
Retention policy определяет, как долго аннотация сохраняется:
SOURCE— только в исходном коде (например,@Override);CLASS— в .class файле, но не загружается в JVM (по умолчанию);RUNTIME— доступна во время выполнения через рефлексию (например,@Test).
Вопрос
Что такое сериализация в Java?
Ответ
Сериализация — это процесс преобразования объекта в последовательность байтов для сохранения в файл, передачи по сети и т.п. Обратный процесс — десериализация.
Класс должен реализовывать Serializable. Поля, помеченные transient, не сериализуются.
Вопрос
Зачем нужен serialVersionUID?
Ответ
serialVersionUID — это уникальный идентификатор версии сериализуемого класса. При десериализации JVM проверяет его соответствие. Если не объявлен явно, генерируется автоматически на основе структуры класса, что может вызвать InvalidClassException при изменении класса.
Вопрос
Что такое клонирование глубокое и поверхностное?
Ответ
- Поверхностное клонирование: создаётся новый объект, но поля-ссылки указывают на те же объекты, что и оригинал.
- Глубокое клонирование: рекурсивно клонируются все вложенные объекты, создавая полностью независимую копию.
Object.clone() по умолчанию даёт поверхностную копию.
Вопрос
Как обеспечить безопасность в Java-приложении?
Ответ
Основные меры:
- Валидация входных данных;
- Использование параметризованных запросов (защита от SQL-инъекций);
- Шифрование чувствительных данных;
- Минимизация привилегий (принцип наименьших привилегий);
- Регулярное обновление зависимостей (проверка через
OWASP Dependency-Check); - Использование
SecurityManager(устаревает, но иногда применяется).
Вопрос
Что такое immutability и зачем она нужна?
Ответ
Неизменяемость — это свойство объекта, состояние которого нельзя изменить после создания. Преимущества:
- Потокобезопасность без синхронизации;
- Упрощение логики программы;
- Безопасная передача и совместное использование.
Примеры: String, LocalDateTime, записи (record).
Вопрос
Какие принципы SOLID применимы в Java?
Ответ
SOLID — это пять принципов проектирования ООП:
- Single Responsibility — один класс — одна обязанность;
- Open/Closed — открыт для расширения, закрыт для изменения;
- Liskov Substitution — подклассы должны быть взаимозаменяемы с суперклассами;
- Interface Segregation — много узкоспециализированных интерфейсов лучше одного общего;
- Dependency Inversion — зависимости должны строиться на абстракциях, а не реализациях.
Вопрос
Какие лучшие практики написания Java-кода вы знаете?
Ответ
Ключевые практики:
- Использовать осмысленные имена переменных и методов;
- Избегать магических чисел и строк;
- Предпочитать композицию наследованию;
- Писать маленькие, сфокусированные методы;
- Использовать
finalдля неизменяемых ссылок; - Не игнорировать исключения;
- Покрывать код тестами (JUnit, TestNG);
- Следовать стандартам форматирования (Google Java Style, Oracle Code Conventions).