Java Core¶
- Java Platform: JDK, JRE, JVM, GC
- Collection API
- Multithreading
- Patterns
-
https://habr.com/ru/articles/485678/
- https://javarush.com/groups/posts/2590-top-50-java-core-voprosov-i-otvetov-na-sobesedovanii-chastjh-1
- https://javastudy.ru/interview/list-of-question-java-interview/
- https://javastudy.ru/interview/list-of-questions-javaee-interview/
Java Особенности¶
- Язык Java. Особенности языка
ООП¶
ООП — методология программирования, где основные конструктивные элементы — объекты, а не алгоритмы.
- Класс — шаблон (поля + методы + конструктор)
- Объект — экземпляр класса
Принципы ООП
| Принцип | Описание |
|---|---|
| Инкапсуляция | Объединение данных и методов в одной «капсуле», защита от внешнего вмешательства |
| Наследование | Описание нового класса на основе уже существующего |
| Полиморфизм | Единообразная обработка объектов с разной реализацией через общий интерфейс |
Виды полиморфизма
- Ad hoc — перегрузка/переопределение метода
- Параметрический — один метод работает с разными типами одинаково
- Subtype — самый популярный: объекты с одинаковой спецификацией имеют разную реализацию
Плюсы и минусы ООП
| ✅ Преимущества | ❌ Недостатки |
|---|---|
| Читаемый, структурированный код | Объекты потребляют больше памяти |
| Быстрое создание сущностей | Снижение производительности |
| Меньше дублирования кода | Излишняя универсальность |
| Простая реализация большого функционала | Сложнее начать, чем функциональное программирование |
Связи между объектами
| Тип | Описание | Пример |
|---|---|---|
| Ассоциация | Связь между объектами | Менеджер выписывает Счёт |
| Агрегация | Один объект — часть другого; объекты равноправны | Студент входит в Группу |
| Композиция | Жёсткая зависимость: часть не может существовать без целого | Двигатель внутри Машины |
SOLID
| Принцип | Суть |
|---|---|
| S — Single Responsibility | Один класс — одна ответственность |
| O — Open/Closed | Открыт для расширения, закрыт для изменения |
| L — Liskov Substitution | Наследник должен заменять родителя без изменения поведения |
| I — Interface Segregation | Лучше много узких интерфейсов, чем один широкий |
| D — Dependency Inversion | Зависимость от абстракций, не от конкретных реализаций |
ООП в Java: Виды классов
| Вид | Описание |
|---|---|
| Обычный класс | — |
| Абстрактный класс | Нельзя создать экземпляр; может содержать абстрактные методы |
| final класс | Запрещено наследование |
| Вложенный (inner) | Нестатический класс внутри класса; имеет доступ к полям внешнего |
| Статический вложенный | static класс внутри класса; доступ только к статическим полям внешнего |
| Локальный класс | Объявлен внутри метода; работает с final/effectively final переменными |
| Анонимный класс | Локальный класс без имени; создаётся и объявляется одновременно |
| enum | Набор логически связанных констант |
Модификаторы доступа
| Модификатор | Класс | Пакет | Наследники | Все |
|---|---|---|---|---|
private |
✅ | ❌ | ❌ | ❌ |
default |
✅ | ✅ | ❌ | ❌ |
protected |
✅ | ✅ | ✅ | ❌ |
public |
✅ | ✅ | ✅ | ✅ |
Класс верхнего уровня может быть только
publicилиdefault.
Модификаторы: static, final, abstract
static
- Переменная — принадлежит классу, не объекту
- Метод — нельзя переопределить (только скрыть — hiding); можно перегрузить
- Класс — только вложенный; имеет доступ лишь к статике внешнего класса
- Внутри static метода нельзя вызвать нестатический метод по имени класса
final
- Класс — запрещено наследование (несовместим с abstract)
- Метод — запрещено переопределение
- Переменная-примитив — нельзя изменить значение
- Переменная-ссылка — нельзя изменить ссылку, но можно изменить состояние объекта
abstract
- Класс не может быть инстанциирован
- Может быть без абстрактных методов
- Абстрактный класс может иметь конструкторы (для наследников)
Конструкторы
| Тип | Описание |
|---|---|
| По умолчанию | Без аргументов; генерируется компилятором, если нет других конструкторов |
| С параметрами | Аргументы для инициализации полей |
| Копирования | Принимает объект того же класса и создаёт его клон |
privateконструктор — запрещает создание экземпляра извне (Singleton, фабричные методы)- Если определён хотя бы один конструктор — дефолтный автоматически не создаётся
Интерфейсы vs Абстрактные классы
| Интерфейс | Абстрактный класс | |
|---|---|---|
| Поля | public static final |
Любые |
| Методы | public abstract + default (Java 8+) |
Любые |
| Конструктор | ❌ | ✅ |
| Наследование | Множественное (implements) |
Одиночное (extends) |
| Когда использовать | Общее поведение несвязанных классов | Отношение «is-a», общее состояние |
Ромбовидное наследование
Java не поддерживает множественное наследование классов.
Для конфликтующих default методов интерфейсов — явное разрешение:
Правила приоритета:
1. Метод класса/суперкласса > default интерфейса
2. Более специфичный интерфейс побеждает менее специфичный
3. Иначе — явное указание через super
- Простое и множественное наследование. Особенности реализации наследования в Java
- Понятие абстрактного класса. Модификатор abstract
- Понятие интерфейса. Реализация интерфейсов в Java. Отличие интерфейсов от абстрактных классов
Класс Object¶
Базовый класс для всех классов в Java.
| Метод | Описание |
|---|---|
equals(Object) |
Сравнение по состоянию |
hashCode() |
Целочисленный хэш объекта |
toString() |
Строковое представление |
getClass() |
Тип объекта |
clone() |
Поверхностное копирование |
finalize() |
⚠️ Deprecated; вызывается GC перед удалением |
notify() |
Размораживает один случайный поток монитора |
notifyAll() |
Размораживает все потоки монитора |
wait() |
Поток освобождает монитор и ждёт |
Методы объекта Object (wait, notify, notifyAll, hashCode, equals, clone)
equals() и hashCode()
Контракт
- Если
hashCodeразные → объекты гарантированно разные - Если
equals→true, тоhashCodeдолжны быть равны - Переопределил
equals→ обязан переопределитьhashCode
Свойства equals()
- Рефлексивность:
x.equals(x) == true - Симметричность:
a.equals(b) == b.equals(a) - Транзитивность: если
a.equals(b)иb.equals(c)→a.equals(c) - Постоянство: повторные вызовы возвращают одно и то же значение
Алгоритм переопределения equals()
@Override
public boolean equals(Object o) {
if (this == o) return true; // 1. проверка ссылок
if (!(o instanceof MyClass)) return false; // 2. проверка типа + null
MyClass other = (MyClass) o; // 3. приведение типа
return Objects.equals(field1, other.field1) && field2 == other.field2; // 4. сравнение полей
}
Правила переопределения hashCode()
- Используй те же поля, что и в
equals() - Повторный вызов на том же объекте → тот же результат
- Предпочтительнее:
31 * x + y(зависимость от порядка полей), чемx + y - Коллизия (одинаковые hashCode у разных объектов) — допустима, но нежелательна
enum¶
- Неявно наследует
java.lang.Enum - Может реализовывать интерфейсы, но не наследовать классы
- Конструктор всегда
private - Можно создать Singleton на основе enum
| Метод | Описание |
|---|---|
ordinal() |
Порядковый номер константы (с 0) |
values() |
Массив всех констант |
valueOf(String) |
Константа по имени |
Плюсы над static final int: проверка типов на этапе компиляции.
Минусы: нельзя использовать >, <, >=, <=; занимает больше памяти.
record¶
Сигнатура и передача параметров¶
- Сигнатура метода = имя + параметры (порядок важен)
- Тип возврата и исключения в сигнатуру не входят
- Контракт метода = сигнатура + тип возврата + throws
Передача параметров
Java всегда передаёт параметры по значению!
- Примитивы — передаётся копия значения
- Объекты — передаётся копия ссылки (объект не копируется)
Переопределение vs Перегрузка
| Переопределение (Override) | Перегрузка (Overload) | |
|---|---|---|
| Сигнатура | Та же | Разная (имя то же) |
| Возвращаемый тип | Нельзя расширить, можно сузить | Любой |
| Модификатор доступа | Только расширить | Любой |
static методы |
Нельзя (только скрыть) | Можно |
throws |
Можно добавить подтипы/RuntimeException | Любой |
Виды ссылок в Java¶
| Тип | Поведение GC |
|---|---|
| StrongReference | Обычная ссылка; GC не удалит объект |
| SoftReference | Удаляется перед OutOfMemoryError; используется для кэша |
| WeakReference | Удаляется при следующей сборке, если нет strong-ссылок |
| PhantomReference | Удаляется после finalize(); get() всегда null; используется с ReferenceQueue |
Кратко: Soft — пытается сохранить. Weak — не пытается. Phantom — не освобождает, пока не очищен явно.
Память: Stack и Heap¶
| Stack | Heap | |
|---|---|---|
| Содержит | Фреймы методов, локальные переменные-примитивы, ссылки | Объекты |
| Доступ | Только из текущего потока | Из всей программы |
| Размер | Меньше | Больше |
| Скорость | Быстрее | Медленнее |
| Ошибка переполнения | StackOverflowError |
OutOfMemoryError |
- PermGen (до Java 7) — метаданные классов, статика, пул строк
- MetaSpace (с Java 8) — заменяет PermGen, хранится вне основной кучи
Типы данных¶
Примитивные типы
| Тип | Размер | Описание |
|---|---|---|
byte |
1 байт | Целое [-128; 127] |
short |
2 байта | Целое |
int |
4 байта | Целое |
long |
8 байт | Целое (суффикс L) |
float |
4 байта | Вещественное (суффикс f) |
double |
8 байт | Вещественное (суффикс d) |
char |
2 байта | Символ UTF-16 (беззнаковый) |
boolean |
~4 байта | true/false |
Значения по умолчанию
| Тип | Значение |
|---|---|
| Числовые | 0 / 0L / 0.0f / 0.0d |
char |
'\u0000' |
boolean |
false |
| Объекты | null |
Локальные переменные в методе не имеют значений по умолчанию — только поля класса.
Приведение типов
| Вид | Описание |
|---|---|
| Неявное (расширение) | Автоматически от меньшего к большему (int → long) |
| Явное (сужение) | Нужно указать тип явно ((int) longValue) |
- Объекты: неявно наследник → родитель; явно родитель → наследник (иначе
ClassCastException) -
Классы-оболочки. Назначение, область применения, преимущества и недостатки. Автоупаковка и автораспаковка¶
Обёртки и Autoboxing¶
- Обёртка — класс, хранящий значение примитива (
Integer,Long,Booleanи др.) - Объекты-обёртки неизменяемы (Immutable)
- Нужны для дженериков и коллекций
| Термин | Описание |
|---|---|
| Автоупаковка (boxing) | int → Integer автоматически |
| Автораспаковка (unboxing) | Integer → int автоматически |
Пул Integer: значения в диапазоне [-128; 127] берутся из кэша JVM.
Изменить размер кэша: -XX:AutoBoxCacheMax=<размер>
Строки¶
| Класс | Изменяемость | Потокобезопасность |
|---|---|---|
String |
Неизменяемый | Да |
StringBuffer |
Изменяемый | Да (synchronized) |
StringBuilder |
Изменяемый | Нет |
Пул строк (String Pool)
- Хранится в Heap
- При создании строки: если строка уже есть в пуле — возвращается ссылка на неё
new String("...")— создаёт объект вне пулаintern()— помещает строку в пул
Почему String неизменяемый?
- Реализация пула строк (интернирование)
- Безопасность (параметры авторизации, файлы)
- Потокобезопасность
- Кэширование
hashCode()— строка — отличный ключ дляHashMap
Почему не хранить пароли в String?
- Строка остаётся в пуле до GC — уязвимость
- Используй
char[]и очищай после использования
Порядок инициализации¶
1. Статические блоки: от предка к наследнику
2. Динамические блоки инициализации + конструктор: попарно от предка к наследнику
Исключения в блоках инициализации:
- Статический блок: явный throw → ошибка компиляции
- Если исключение — наследник RuntimeException в static блоке → ExceptionInInitializerError
Исключения¶
Иерархия
Throwable (checked)
├── Error (unchecked) — ошибки JVM
│ ├── StackOverflowError
│ └── OutOfMemoryError
└── Exception (checked)
├── IOException
├── SQLException
└── RuntimeException (unchecked)
├── NullPointerException
├── ClassCastException
├── IndexOutOfBoundsException
└── ArithmeticException
| Тип | Когда обрабатывать | Пример |
|---|---|---|
| Checked | Обязательно: catch или throws |
IOException |
| Unchecked | Опционально | NullPointerException |
Try-catch-finally
try {
// код, где может быть исключение
} catch (IOException | SQLException e) {
// обработка (от наследника к предку)
} finally {
// выполняется всегда*
}
finallyне выполняется при:System.exit(),Runtime.halt(), бесконечном цикле вtry, фатальной ошибке JVM.
Try-with-resources (Java 7+)
Класс ресурса должен реализовывать AutoCloseable или Closeable.
Если оба блока (try и close()) бросают исключение — побеждает исключение из try, второе подавляется (getSuppressed()).
Ключевые слова
| Ключевое слово | Назначение |
|---|---|
throw |
Принудительно выбросить исключение |
throws |
Объявить, что метод может выбросить исключение |
Сериализация и Клонирование¶
Сериализация — сохранение состояния объекта в последовательность байт.
// Реализовать интерфейс-маркер
class MyClass implements Serializable {
private static final long serialVersionUID = 1L;
transient String password; // НЕ будет сериализован
static int count; // НЕ будет сериализован
}
| Поле | Сериализуется? |
|---|---|
| Обычное поле | ✅ |
transient |
❌ (станет null) |
static |
❌ |
final |
✅ (кроме Externalizable) |
Кастомная сериализация: реализовать Externalizable и переопределить writeExternal() / readExternal().
serialVersionUID — идентификатор версии класса. Изменять только при сознательном разрыве совместимости.
Проблема Singleton при сериализации: десериализация создаёт новый объект. Решение — добавить метод readResolve().
Интерфейс Serializable. Объектный граф, сериализация и десериализация полей и методов
Клонирование
| Способ | Описание |
|---|---|
Cloneable + clone() |
Поверхностное копирование; clone() — protected, нужно переопределить |
| Конструктор копирования | Предпочтительный способ; явное копирование полей; работает с final |
| Сериализация | Глубокое копирование через сериализацию/десериализацию |
| Поверхностное | Глубокое | |
|---|---|---|
| Примитивы | Копируются | Копируются |
| Ссылочные поля | Копируется ссылка | Копируется объект |
Правила создания неизменяемого (Immutable) класса:
- Все поля private final
- Нет сеттеров
- Класс объявить final
- Для изменяемых полей-объектов — возвращать защитные копии
Дженерики (Generics)¶
Дженерики — параметризованные типы. Информация о типе доступна только при компиляции (стирание типов в runtime).
List<String> list = new ArrayList<>(); // дженерик
List list = new ArrayList(); // raw type (тип стирается → Object)
Wildcards
| Синтаксис | Название | Можно читать | Можно писать |
|---|---|---|---|
? extends T |
Верхняя граница (ковариантность) | ✅ | ❌ (только null) |
? super T |
Нижняя граница (контравариантность) | ❌ (только Object) |
✅ |
<?> |
Неограниченный | ✅ | ❌ |
Принцип PECS
Producer Extends, Consumer Super
- Получаешь объекты из коллекции →
extends(producer) - Кладёшь объекты в коллекцию →
super(consumer) - Делаешь оба → не используй wildcard
// Producer: только читаем
void copy(List<? extends Number> src) { ... }
// Consumer: только пишем
void fill(List<? super Integer> dest) { ... }
Функциональные интерфейсы¶
Функциональный интерфейс — интерфейс, содержащий ровно один абстрактный метод.
- Может иметь сколько угодно
defaultиstaticметодов — они не абстрактные - Аннотация
@FunctionalInterface— не обязательна, но рекомендуется: компилятор проверит контракт и не даст добавить второй абстрактный метод
@FunctionalInterface
interface Converter<F, T> {
T convert(F from); // единственный абстрактный метод
default void log() { ... } // можно
static void util() { ... } // можно
}
Встроенные функциональные интерфейсы (java.util.function)
| Интерфейс | Сигнатура | Принимает | Возвращает | Описание |
|---|---|---|---|---|
Predicate<T> |
boolean test(T t) |
T | boolean | Проверка условия |
Consumer<T> |
void accept(T t) |
T | void | Выполняет действие, ничего не возвращает |
Supplier<T> |
T get() |
— | T | Ничего не принимает, возвращает результат |
Function<T,R> |
R apply(T t) |
T | R | Преобразует T в R |
UnaryOperator<T> |
T apply(T t) |
T | T | Операция над одним аргументом того же типа |
BinaryOperator<T> |
T apply(T t1, T t2) |
T, T | T | Операция над двумя аргументами того же типа |
BiFunction<T,U,R> |
R apply(T t, U u) |
T, U | R | Два аргумента, разные типы |
BiConsumer<T,U> |
void accept(T t, U u) |
T, U | void | Два аргумента, без результата |
BiPredicate<T,U> |
boolean test(T t, U u) |
T, U | boolean | Проверка для двух аргументов |
Mнемоника:
Predicate → тест (да/нет)
Consumer → потребляет, ничего не отдаёт
Supplier → только поставляет
Function → T → R (трансформация)
Operator → T → T (тот же тип)
Примитивные специализации (без boxing overhead)
| Интерфейс | Описание |
|---|---|
IntPredicate, LongPredicate, DoublePredicate |
Predicate для примитивов |
IntConsumer, LongConsumer, DoubleConsumer |
Consumer для примитивов |
IntSupplier, LongSupplier, DoubleSupplier |
Supplier для примитивов |
IntFunction<R>, ToIntFunction<T> |
Function с примитивами |
IntUnaryOperator, IntBinaryOperator |
Операторы для int |
Лямбда — упрощённая запись анонимного класса, реализующего функциональный интерфейс.
// Анонимный класс (старый стиль)
Runnable r1 = new Runnable() {
@Override
public void run() { System.out.println("Hello"); }
};
// Лямбда (новый стиль)
Runnable r2 = () -> System.out.println("Hello");
Синтаксис лямбды
// Базовый синтаксис: (параметры) -> тело
(параметры) -> выражение
(параметры) -> { блок; операторов; }
// Примеры:
() -> 42 // нет параметров
x -> x * x // один параметр (скобки необязательны)
(x, y) -> x + y // два параметра
(int x, int y) -> { return x + y; } // с явными типами и return
Пример с разными интерфейсами
Predicate<String> isEmpty = s -> s.isEmpty();
Consumer<String> printer = s -> System.out.println(s);
Supplier<String> greeting = () -> "Hello!";
Function<String, Integer> len = s -> s.length();
UnaryOperator<String> upper = s -> s.toUpperCase();
BinaryOperator<Integer> sum = (a, b) -> a + b;
Ключевое преимущество лямбды — отложенное выполнение (deferred execution): определяем в одном месте, вызываем сколько угодно раз в разных местах программы.
Ссылки на методы (Method References)
Сокращённый синтаксис лямбды, которая вызывает только один метод.
| Вид | Синтаксис | Эквивалент лямбды |
|---|---|---|
| Статический метод | ClassName::staticMethod |
(args) -> ClassName.staticMethod(args) |
| Метод экземпляра (конкретного) | object::instanceMethod |
(args) -> object.instanceMethod(args) |
| Метод экземпляра (произвольного) | ClassName::instanceMethod |
(obj, args) -> obj.instanceMethod(args) |
| Конструктор | ClassName::new |
(args) -> new ClassName(args) |
// Статический метод
Function<String, Integer> parse = Integer::parseInt;
// Метод конкретного экземпляра
String prefix = "Hello, ";
Function<String, String> greet = prefix::concat;
// Метод произвольного экземпляра
Function<String, String> upper = String::toUpperCase;
// Конструктор
Supplier<ArrayList<String>> factory = ArrayList::new;
Композиция функциональных интерфейсов
// Function: andThen (сначала f, потом g) и compose (сначала g, потом f)
Function<Integer, Integer> times2 = x -> x * 2;
Function<Integer, Integer> plus3 = x -> x + 3;
Function<Integer, Integer> times2ThenPlus3 = times2.andThen(plus3); // (x*2)+3
Function<Integer, Integer> plus3ThenTimes2 = times2.compose(plus3); // (x+3)*2
// Predicate: and, or, negate
Predicate<Integer> isPositive = x -> x > 0;
Predicate<Integer> isEven = x -> x % 2 == 0;
Predicate<Integer> positiveAndEven = isPositive.and(isEven);
Predicate<Integer> positiveOrEven = isPositive.or(isEven);
Predicate<Integer> isNegative = isPositive.negate();
Замыкание (Closure) Лямбда может захватывать переменные из внешнего контекста, но только effectively final (не изменяемые после инициализации):
int multiplier = 3; // effectively final — OK
// multiplier = 5; // ← если раскомментировать, лямбда не скомпилируется
Function<Integer, Integer> mult = x -> x * multiplier;
Почему? Лямбда живёт дольше стека метода. Изменяемая переменная создала бы гонку данных.
Потоки ввода-вывода в Java. Байтовые и символьные потоки. "Цепочки" потоков (Stream Chains)¶
- Работа с файлами в Java. Класс java.io.File
- Пакет java.nio - назначение, основные классы и интерфейсы
Network¶
- Протокол TCP. Классы Socket и ServerSocket
- Протокол UDP. Классы DatagramSocket и DatagramPacket
- Отличия блокирующего и неблокирующего ввода-вывода, их преимущества и недостатки. Работа с сетевыми каналами
- Классы SocketChannel и DatagramChannel
JDBC¶
- JDBC. Порядок взаимодействия с базой данных. Класс DriverManager. Интерфейс Connectio
- Интерфейсы Statement, PreparedStatement, ResultSet, RowSe