Java Core #
1. Расскажи мне про контракт и свойства Equals & Hashcode #
Контракт:
- Если
hashCode()двух объектов возвращает разные значения, то они не могут быть равны - Если
equals()объектов true, то и хеш-коды должны быть равны - Переопределив
equals(), всегда переопределятьhashCode() - Если у объектов одинаковый
hashCode(), то они не обязательноequals() - При каждом вызове
hashCode()для одного и того же объекта должен возвращаться один и тот же хеш-код
Свойства equals():
Метод equals() реализует отношение равенства (эквивалентности), которое обладает следующими свойствами:
- Рефлексивность. Объект должен быть равен самому себе (
x.equals(x) == true) - Симметричность. Любые два объекта должны иметь одно и то же мнение относительно своего равенства или неравенства (
x.equals(y) == trueиy.equals(x) == true) - Транзитивность. Если один объект равен второму, а второй равен третьему, то и первый объект должен быть равен третьему (
x.equals(y) == trueиy.equals(z) == trueиx.equals(z) == true) - Непротиворечивость. Если два объекта равны, они должны быть равны всегда, пока один из них (или оба они) не будет изменен
- Для любой ненулевой ссылки на значение
хвыражениех.equals(null)должно возвращатьfalse.
Свойства hashCode():
- Согласованность. При каждом вызове
hashCode()для одного и того же объекта в рамках одной программы должно возвращаться одно и то же значение, если поля объекта, участвующие в расчете хеш-кода, не изменились - Равенство и хеш-код. Если два объекта равны по методу
equals(), их хеш-коды тоже должны быть равны. Однако обратное не обязательно — объекты с одинаковым хеш-кодом могут быть не равны - Распределение. Реализация
hashCode(), возвращающая разный хеш-код для неравных объектов позволяет увеличить эффективность работы с хеш-структурами данных (такими как HashMap или HashSet) за счёт распределения объектов по разным корзинам хеш-таблицы
2. Что такое коллизия? #
Коллизия возникает, когда у разных объектов одинаковые хеш-коды
Что будет, если переопределить equals() не переопределяя hashCode()?
- Объект, который по
equals()равен существующему ключу в HashMap, может не быть найден, если их хеш-коды различаются. Это связано с тем, что HashMap сначала используетhashCode()для поиска корзины, а уже потом сравнивает объекты поequals(). - При попытке удалить ключ, который равен другому ключу по
equals(), но имеет другойhashCode(), удаление может не сработать.
3. Какие типы ссылок существуют в Java? #
Типы ссылок в Java:
- Сильная ссылка - объект не будет удален сборщиком мусора, пока на него есть хотя бы одна сильная ссылка
Object a = new Object() - Мягкая ссылка - используется для кеширования. Объект, на который ссылается мягкая ссылка, будет удален сборщиком мусора только при нехватке памяти
SoftReference<MyObject> softRef = new SoftReference<>(new MyObject()) - Слабая ссылка - объект, на который она ссылается, может быть удалён при следующем вызове сборщика мусора
WeakReference<MyObject> weakRef = new WeakReference<>(new MyObject()) - Фантомная ссылка - используется для отслеживания, когда объект был удалён из памяти. Фантомная ссылка не позволяет получить доступ к объекту напрямую, она только сигнализирует, что объект скоро будет удален
PhantomReference<MyObject> phantomRef = new PhantomReference<>(new MyObject(), referenceQueue)
4. Какой класс называют Immutable? #
Иммутабельный класс - класс, экземпляры которого не могут быть изменены после создания. Принципы создания:
- модификатор
finalу класса - все поля
private final - отсутствие сеттеров
- все поля задаются через конструктор
5. Основная идея языка #
Написано однажды - работает везде
6. За счет чего обеспечена кроссплатформенность? #
За счёт того, что исходный код компилируется в байт-код, который затем исполняется виртуальной машиной Java (JVM).
7. Плюсы и минусы Java? #
Плюсы:
Объектно-ориентированное программирование. Структура данных становится объектом, которым можно управлять, создавать отношения между различными объектами.
Язык высокого уровня с простым синтаксисом и плавной кривой обучения. Синтаксис Java основан на C ++, поэтому Java похожа на C. Тем не менее, синтаксис Java проще, что позволяет новичкам быстрее учиться и эффективнее использовать код для достижения конкретных результатов.
Стандарт для корпоративных вычислительных систем. Корпоративные приложения — главное преимущество Java с 90-х годов, когда организации начали искать надежные инструменты программирования не на C.
Безопасность. Благодаря отсутствию указателей и Security Manager (политика безопасности, в которой можно указать правила доступа, позволяет запускать приложения Java в “песочнице”).
Независимость от платформы. Можно создать Java-приложение на Windows, скомпилировать его в байт-код и запустить его на любой другой платформе, поддерживающей виртуальную машину Java (JVM). Таким образом, JVM служит уровнем абстракции между кодом и оборудованием.
Язык для распределенного программирования и комфортной удаленной совместной работы. Специфическая для Java методология распределенных вычислений называется Remote Method Invocation (RMI). RMI позволяет использовать все преимущества Java: безопасность, независимость от платформы и объектно-ориентированное программирование для распределенных вычислений. Кроме того, Java также поддерживает программирование сокетов и методологию распределения CORBA для обмена объектами между программами, написанными на разных языках.
Автоматическое управление памятью. (вопрос спорный: плюс или минус) Разработчикам Java не нужно вручную писать код для управления памятью благодаря автоматическому управлению памятью (AMM).
Многопоточность. Поток — наименьшая единица обработки в программировании. Чтобы максимально эффективно использовать время процессора, Java позволяет запускать потоки одновременно, что называется многопоточностью.
Стабильность и сообщество. Сообщество разработчиков Java не имеет себе равных. Около 45% респондентов опроса StackOverflow 2018 используют Java.
Минусы:
- Платное коммерческое использование (с 2019)
- Многословный код
8. JVM, JRE, JDK, JIT #
JVM (Java Virtual Machine) - виртуальная машина Java, исполняющая байт-код. JRE (Java Runtime Environment) - JVM + набор стандартных библиотек, необходимых для запуска приложений Java:
- java.lang - String, System, Object
- java.io - InputStream, OutputStream
- java.util - коллекции (List, Set, Map) JDK (Java Development Kit) - набор разработчика, включает JRE + компилятор и другие инструменты JIT(C) (Just-In-Time Compilation) - компиляция байт-кода в машинный во время выполнения программы. Позволяет ускорить выполнение программы за счёт компиляции наиболее часто выполняемых участков кода в машинный код и хранения его в памяти
9. Что такое байт-код? #
Байт-код - это набор инструкций, исполняемый JVM, получаются из исходного кода путём компиляции.
10. Что такое сборщик мусора (garbage collector)? #
Сборщик мусора - это механизм JVM, отвечающий за управление объектами в памяти. Программист выделяет память под объекты, поиском и очищением памяти от неиспользуемых объектов (объектов, на которые нет прямых или косвенных ссылок) занимается сборщик.
| Версия Java | GC по умолчанию | Примечания |
|---|---|---|
| Java 8 | Parallel GC | Оптимизирован для пропускной способности. |
| Java 9 | G1 | G1 стал сборщиком по умолчанию, заменив Parallel GC. |
| Java 10 | G1 | Улучшения в G1, включая параллельную полную сборку мусора. |
| Java 11 | G1 | Введены ZGC и Shenandoah (экспериментальные). |
| Java 12 | G1 | Улучшения в G1, включая возврат неиспользуемой памяти. |
| Java 13 | G1 | Улучшения в ZGC и Shenandoah. |
| Java 14 | G1 | ZGC и Shenandoah стали стабильными. |
| Java 15 | G1 | ZGC стал кроссплатформенным. |
| Java 16 | G1 | Улучшения в ZGC и Shenandoah. |
| Java 17 | G1 | CMS окончательно удален. |
| Java 21 | G1 | Введен Generational ZGC, улучшения в G1, ZGC и Shenandoah. |
Когда использовать другие GC?
- ZGC - для приложений с огромными кучами (терабайты) и требованиями к минимальным паузам (менее 10 мс).
- Shenandoah - для приложений с низкими задержками и большими кучами.
- Parallel GC - для приложений, где важна пропускная способность, а не низкие задержки.
- Serial GC - для однопоточных приложений или приложений с небольшими кучами.
11. Как работает GC? #
- Поиск недостижимых объектов - проверяет, есть ли ссылки на объект.
- Очистка - если объект недостижим, его память освобождается.
- Обновление памяти - освобождённая память становится доступной для новых объектов.
Основные алгоритмы GC:
- Mark-and-Sweep - отмечает используемые объекты и удаляет неиспользуемые.
- Generational GC - разделяет память на молодое, старшее и постоянное поколение для оптимизации работы.
12. Какие виды GC знаешь? #
- Serial GC — простой однопоточный сборщик мусора, который хорошо подходит для маленьких приложений и небольшого объёма памяти.
- Parallel GC (Throughput GC) — многопоточный сборщик, который делает упор на максимальную производительность приложения.
- CMS (Concurrent Mark Sweep) — сборщик с низкими паузами, который пытался выполнять часть работы параллельно с приложением, но сейчас считается устаревшим.
- G1 GC (Garbage First) — универсальный сборщик, который балансирует между скоростью работы и предсказуемыми паузами.
- ZGC — современный сборщик для приложений, где важны ультранизкие паузы, обычно в пределах миллисекунд.
- Shenandoah — low-latency сборщик, похожий по назначению на ZGC, тоже старается минимизировать паузы приложения.
- Epsilon GC — специальный сборщик, который вообще не освобождает память и используется в основном для тестов и бенчмарков.
13. Области памяти Java. Stack и heap. Что это такое? #

На рисунке структура памяти JVM согласно спецификации
Разбираем с т.з. спецификации и реализации в HotSpot JVM.
Нативная память (native memory) - это вся память, которую процесс JVM получает напрямую от операционной системы. Внутри у неё есть heap, все остальные области - в нативной памяти.
Heap (куча) - используется для выделения памяти под объекты и классы. Создание нового объекта также происходит в куче. Любой объект, созданный в куче, имеет глобальный доступ и на него могут ссылаться из любой части приложения. Управляется сборщиком мусора. В реализации HotSpot делится на:
- Young Generation - для недавно созданных объектов
- Eden Space - сюда попадают новосозданные объекты, GC проходит здесь чаще всего
- Survivor Space - делится надвое (S1, S2), из Eden “выжившие” объекты переходят в S1, пережившие несколько сборок в S1 переходят в S2
- Old Generation - для долго живущих объектов
- (до Java 8) Perm Generation - хранение статических объектов, размер ограничен
Method Area (MetaSpace для HotSpot) - хранит структуру классов, такую как метаданные классов, пул констант, статические переменные и код методов. Доступна всем потокам в JVM. В Java 8 MetaSpace заменила PermGen (который был частью кучи) и, в отличие от него, её размер увеличивается автоматически и не имеет явного ограничения
Stack Area - это область хранения стеков (Thread Stack). Стек создаётся при старте потока и доступен только из своего потока. Стек хранит фреймы (те самые строки в нижнем левом углу в режиме отладки в IntelliJ), которые создаются при вызове метода и удаляются при выходе из него. Фреймы хранятся в стеке по принципу LIFO (последний вошёл — первый вышел)

Фрейм содержит в себе все локальные переменные, требующиеся для выполнения методов. Все локальные переменные примитивных типов полностью хранятся в стеке, локальные переменные-ссылки на объект также хранятся в стеке, но сам объект хранится в куче
Регистры (PC Registers) - у каждого потока есть свой регистр, он хранит адрес текущей инструкции байткода и позволяет JVM продолжать выполнение потока после переключений
Native Method Stack - это область памяти, в которой хранятся стеки для вызова нативных методов, то есть методов, написанных на других языках программирования, таких как C или C++
В дополнение к спецификации в HotSpot есть
- Code Cache - хранит код, оптимизированный JIT-компилятором для быстрого выполнения, используется в процессе “прогрева” JVM. Отдельная область в нативной памяти
- Shared Libs - это нативные библиотеки, подключаемые JVM (libc, libjvm.so, JNI-библиотеки)
14. Типы данных в Java #
В Java есть примитивные и ссылочные типы данных.
Примитивные типы данных:
- byte (0) (8 бит)
- short (0) (16 бит)
- int (0) (32 бит)
- long (0L) (64 бит)
- float (0.0f) (32 бит)
- double (0.0d) (64 бит)
- char (\u0000) (16 бит)
- boolean (false) (зависит от JVM)
15. Что такое класс-обертка? #
Класс-обёртка - это immutable-класс, который представляет примитивный тип данных в виде объекта. Такие классы позволяют хранить null, в отличие от примитивов, где null вызывает NullPointerException. Обёртки содержат полезные статические поля (MIN_VALUE, MAX_VALUE) упрощающие работу с данными.
16. Автоупаковка и автораспаковка #
Автоупаковка (autoboxing) - примитивный тип -> класс-обёртка
int x = 10;
Integer obj = x;
Автораспаковка (unboxing) - класс-обёртка -> примитивный тип
Integer obj = 10;
int x = obj;
17. Строки/String в Java? Из чего состоит? Нюансы #
String в Java - это объект. Сравнение через оператор == сравнивает строки по ссылкам объектов - если ссылки равны, то строки равны, в остальных случаях не равны. Нужно использовать equals() и производные методы для сравнения содержимого.
Класс String - immutable из-за модификатора final и отсутствия сеттера. При редактировании строк будет создаваться новая строка.
18. Что такое пул строк/String pool? #
Пул строк — это особая область кучи (heap), где хранятся объекты строк. Служит в первую очередь для оптимизации работы со строковыми литералами. При объявлении литерала (строки в двойных кавычках) в пуле происходит поиск этой строки:
- Если такой строки в пуле нет ⇒ создается строка, возвращается ссылка
- Если есть ⇒ возвращается ссылка найденной строки
Строки, созданные с помощью new String() не помещаются в пул строк и хранятся в куче как остальные объекты.
Что делает метод intern() в классе String?
- Помещает строку в пул строк
19. Почему не рекомендуется изменять строки в цикле? #
Строка является неизменной и финализированной в Java, поэтому все наши манипуляции со строкой всегда будут создавать новую строку. Манипуляции со строками ресурсоемкие, поэтому Java обеспечивает два полезных класса для манипуляций со строками – StringBuffer и StringBuilder.
20. Разница между String, StringBuffer, StringBuilder #
String - неизменяемый, потокобезопасный StringBuilder - изменяемый, оптимизирован для конкатенации строк (новые строки не создаются от каждой конкатенации) StringBuffer - потокобезопасная версия StringBuilder, хуже производительность
21. Каким образом переменные передаются в методы — по значению или по ссылке? #
По значению. Всегда. При передаче объектов передаётся копия ссылки на них. Т.е. внутри метода можно обращаться к объекту и изменять его состояние, но нельзя изменить область памяти, на которую ссылается внешняя переменная
22. Что такое enum? #
Enum - специализированный класс в Java, представляющий из себя набор логически связанных констант. От него нельзя наследоваться.
23. Что такое конструктор? #
Конструктор - это специализированный метод класса, предназначенный для инициализации экземпляра этого класса.
Конструктор по умолчанию - это конструктор без параметров, который автоматически создаётся компилятором, если не было объявлено других конструкторов.
Для чего нужны приватные/private конструкторы?
Приватный конструктор запрещает создание экземпляра класса вне методов самого класса. Нужен для реализации паттернов singleton
public class Singleton {
// Статическое поле для хранения единственного экземпляра класса
private static Singleton instance;
// Приватный конструктор, предотвращающий создание экземпляров извне
private Singleton() {}
// Публичный метод для доступа к единственному экземпляру класса
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
Чем отличаются конструкторы по умолчанию, конструктор копирования и конструктор с параметрами?
- Конструктор по умолчанию - без параметров, дефолтный
- Конструктор копирования - принимает объект того же типа, копирует его поля
- Конструктор с параметрами - принимает на вход параметры для конфигурации объекта при создании
24. Какие есть модификаторы доступа? Какие применимы к классам? #
private- доступ только из класса, в котором объявленdefault- компонент доступен для любого другого класса в том же пакетеprotected- компонент доступен всем классам внутри пакета, а так же всем классам-наследникам вне пакетаpublic- доступ к компоненту из любой точки программы

protected и private в контексте классов применимы только к внутренним (вложенным), потому что в других protected классах нет смысла - default видимость делает то же самое, а к private внешнему классу нельзя было бы обратиться из любого другого класса.
25. Что означает static? #
staticпеременная - переменная, принадлежащая классу, а не объектуstaticкласс - вложенный класс, который может обращаться только к статическим полям класса-оберткиstaticметод - метод, принадлежащий классу, а не объекту. Статические методы обращаются только к другим статическим методам и переменным
Может ли статический метод быть переопределен?
Нельзя переопределять статические методы. Если объявить такой же метод в классе-наследнике, то мы лишь «спрячем» метод суперкласса вместо переопределения. Это называется сокрытие методов.
Прим. Перегружать можно, переопределять нет. В случае со статическими методами это не переопределение (overriding), а сокрытие (hiding).
Могут ли нестатические методы перегружать статические?
Да. В итоге получится два разных метода. Статический будет принадлежать классу и будет доступен через его имя, а нестатический будет принадлежать конкретному объекту и доступен через вызов метода этого объекта.
Могут ли классы быть статическими?
Да, вложенные классы
26. Можно ли сузить уровень доступа или тип возвращаемого значения при переопределении метода? #
Можно расширить модификатор доступа и сузить тип возвращаемого значения (если они совместимы)
27. Что можно изменить в сигнатуре метода при переопределении? Можно ли менять модификаторы (throws и т. п.)? #
Согласно спецификации Java, сигнатура состоит из имени метода, списка параметров и их типов (порядок типов важен). Сюда не входит возвращаемое значение, модификатор доступа и перечисление выбрасываемых исключений.
Поэтому именно в самой сигнатуре при переопределении методов ничего менять нельзя. Можно:
- расширить уровень доступа
- сузить тип возвращаемого значения
- не указывать исключения, которые были объявлены в родительском классе
- добавить новые исключения, которые являются наследниками родительского, либо те, что наследуются от RuntimeException
28. Что означает модификатор final? К чему он может быть применим? #
finalу класса - запрещает наследованиеfinalу примитива - запрещает изменение значения после присвоенияfinalу ссылочной переменной - запрещает изменение ссылки на объектfinalу массива - запрещает изменение ссылки на массив (но можно менять элементы внутри)finalу метода - запрещает переопределять данный метод в наследниках класса
29. Что такое абстрактные классы? #
Абстрактный класс - это класс, который не может быть инстанциирован (нельзя создать экземпляр этого класса). Используется для того, чтобы выделить общую логику (абстракцию) и переиспользовать в наследниках.
Может ли быть абстрактный класс без абстрактных методов? Да, может
Могут ли быть конструкторы у абстрактных классов? Для чего они нужны? Да, могут, если они нужны для наследников
30. Что такое интерфейсы? #
Интерфейс — это особый абстрактный тип, описывающий поведение (контракт), которое классы должны реализовать
- Методы интерфейса - public abstract
- Поля - public static final
Какие модификаторы по умолчанию/по дефолту имеют поля и методы интерфейсов?
Default методы - это методы в интерфейсе, которые имеют тело и помечены default. Классы, реализующие такой интерфейс могут не переопределять метод и использовать код из интерфейса.
Начиная с Java 8 в интерфейсах разрешается размещать реализацию методов по умолчанию default и статических static методов.
По умолчанию все методы в интерфейсе фактически имеют модификатор public. Однако начиная с Java 9 мы также можем определять в интерфейсе методы с модификатором private. Они могут быть статическими и нестатическими, но обязаны иметь реализацию (т.е. тело метода).
Интерфейс также может содержать и поля. В этом случае они автоматически являются публичными public, статическими static и неизменяемыми final.
Может ли один интерфейс наследоваться от другого? От двух других?
Да
Зачем нужны интерфейсы маркеры?
Интерфейсы-маркеры (marker interfaces) — это интерфейсы без методов, используемые для предоставления метаинформации о классе.
Примеры:
Serializable — сообщает, что объект может быть сериализован.Cloneable — разрешает создание копий объекта через clone().
Плюсы:
✅ Простота реализации.
✅ Используется в стандартной библиотеке Java (Serializable, Cloneable).
✅ Позволяет использовать instanceof для проверки типа.
Минусы:
❌ Неявная логика — тяжело понять, что делает интерфейс.
❌ Сложно поддерживать, если нужно добавить новую функциональность.
❌ Нельзя контролировать правильность использования (например, Cloneable не гарантирует корректную реализацию clone()).
Плюсы и минусы дефолтных методов
default-методы позволяют добавлять реализацию методов в интерфейсы без необходимости изменять существующие реализации классов.
Пример:
interface Animal {
default void makeSound() {
System.out.println("Some sound...");
}
}
class Dog implements Animal {}
public class Main {
public static void main(String[] args) {
Dog dog = new Dog();
dog.makeSound(); // Выведет "Some sound..."
}
}
Плюсы:
✅ Позволяют добавлять новые методы в интерфейсы без ломания существующего кода.
✅ Уменьшают дублирование кода в классах, реализующих интерфейс.
✅ Можно предоставлять базовую реализацию метода.
Минусы:
❌ Может усложнять иерархию классов, если использовать слишком активно.
❌ Конфликты default-методов, если несколько интерфейсов содержат метод с одинаковой сигнатурой.
❌ Нарушает принцип единственной ответственности (SRP), так как интерфейс начинает содержать логику.
Плюсы и минусы множественной имплементации
Множественная имплементация означает, что класс может реализовать несколько интерфейсов.
Пример:
interface A {
default void show() {
System.out.println("A");
}
}
interface B {
default void show() {
System.out.println("B");
}
}
class C implements A, B {
@Override
public void show() { // Разрешаем конфликт
A.super.show();
}
}
Плюсы:
✅ Позволяет избежать проблем, связанных с множественным наследованием (алмазная проблема).
✅ Повторное использование кода через default-методы.
✅ Гибкость — можно комбинировать поведение разных интерфейсов.
Минусы:
❌ Конфликты default-методов, если несколько интерфейсов содержат метод с одинаковой сигнатурой.
❌ Возможна сложность в отладке и поддержке кода.
❌ Нельзя использовать super для вызова конструктора интерфейса.
31. Отличия интерфейса от абстрактных классов? #
- Абстрактные классы используются, когда есть отношение “is a”, а интерфейс может быть реализован классами, вовсе не связанными друг с другом
- Унаследовать можно только один класс, а реализовать интерфейсов — сколько угодно
| Критерий | Абстрактный класс | Интерфейс |
|---|---|---|
| Когда использовать | Если есть общая логика, которую наследники могут переопределять | Для определения контрактов, которые реализуют классы |
| Модификаторы доступа по умолчанию | protected, default | Все методы public |
| Наличие конструктора | Да | Нет |
| Наследование/реализация | Класс может наследовать только один абстрактный класс | Класс может реализовать несколько интерфейсов |
| Методы с реализацией | Может содержать методы с реализацией | Может содержать default и static (с Java 8), а с Java 9и private методы с реализацией |
32. Каков порядок вызова конструкторов и блоков инициализации с учетом иерархии классов? #
- Статические блоки у родителя
- Статический блок у наследника
- Нестатический блок у родителя
- Конструктор родителя
- Нестатические блоки у наследника
- Конструктор наследника
33. Зачем нужны и какие бывают блоки инициализации? #
Существуют статические и нестатические блоки инициализации.
Статический блок инициализации используется для инициализации статических данных класса. Он выполняется только один раз, когда класс загружается в память.
Нестатический блок инициализации, также известный как блок инициализации экземпляра, используется для инициализации переменных экземпляра класса. Он выполняется каждый раз, когда создается новый экземпляр класса.
34. Класс Object и его методы? #
Object - базовый класс для всех объектов в Java. Любой класс так или иначе наследуется от Object, и, соответственно, наследует его методы (11 штук):
equals()- определяет, равен ли один объект другому.hashCode()- возвращает хэш-код, связанный с вызывающим объектом.toString()- возвращает символьную строку, описывающую объект.getClass()- получает класс объекта во время выполнения.clone()- создает новый объект, не отличающийся от клонируемого.finalize()- вызывается перед удалением неиспользуемого объекта.
А так же методы для многопоточности:
notify()- возобновляет исполнение потока, ожидающего вызывающего объекта.notifyAll()- возобновляет исполнение всех потоков, ожидающих вызывающего объекта.wait(),wait(long timeout),wait(long timeout, int nanos)- ожидает другого потока исполнения.
Метод finalize()
finalize() — это метод в классе Object, который вызывается перед уничтожением объекта сборщиком мусора (GC). Помечен как @Deprecated с Java 9 с возможностью дальнейшего удаления.
Современная альтернатива:
Java 9+: использовать Cleaner или try-with-resources.
35. Что такое сериализация и для чего она нужна? #
Сериализация - это механизм преобразования объектов в байтовую строку. В Java реализована через интерфейс-маркер Serializable. Нужна для компактного сохранения состояния объекта, передачи по сети и считывания этого состояния
36. Разница между версиями Java #
- Java 8 - лямбда-выражения, Stream API, Optional API, новый Date and Time API,
defaultметоды в интерфейсах - Java 9 - модульная система (JPMS), улучшения в Stream API и методы
Optional.ifPresentOrElse, фабричные методы для коллекций (List.of) - Java 10 - локальная типизация (
var), улучшения в GC, API для создания неизменяемых коллекций (List.copyOf, Set.copyOf, Map.copyOf) - Java 11 - поддержка
varв лямбдах, новый клиент HTTP - Java 17 -
record,sealedклассы, улучшения в GC и performance, pattern matching дляinstanceof - Java 21 - виртуальные потоки, pattern matching для
switch, поддержка sealed-иерархий дляrecord, улучшения в GC - Java 23 -
flexible constructor, javadoc комменты в markdown формате, улучшения по ZGC - Java 25 - улучшения JIT,
scoped valuesвместоThreadLocal,structurred concurrency,stable valueвместо синглтона
37. Может ли абстрактный класс быть final? #
Нет, т.к. суть этого класса - в вынесении общей логики наследников, нельзя создать экземпляр абстрактного класса.
38. Integer pool #
Integer Pool - это область памяти в хипе, предназначенная для кэширования Integer в диапазоне от -128 до 127 для уменьшения количества создаваемых объектов (по аналогии с String Pool)
39. Какие виды загрузчиков классов ты знаешь? #
- Bootstrap ClassLoader: Загружает стандартные библиотеки (например,
rt.jar). - Extension ClassLoader: Загружает дополнительные библиотеки (
ext). - System ClassLoader: Загружает классы из classpath.
- Custom ClassLoader: Пользовательские загрузчики классов.
40. Record-ы с Java 17. Для чего и зачем? #
Record — это компактная декларация неизменяемого класса, удобная для хранения данных.
- Преимущества:
- Автоматическое создание конструктора, getter-ов (методы именуется без префикса get),
equals,hashCode,toString. - Неизменяемость полей.
- Автоматическое создание конструктора, getter-ов (методы именуется без префикса get),
public record Point(int x, int y) {}
Point p = new Point(1, 2);
System.out.println(p.x()); // 1
41. Что такое Анонимный класс #
Анонимный класс - это класс без имени, реализация которого описана in-place в момент создания
Runnable r = new Runnable() {
@Override
public void run() {
System.out.println("Hello!");
}
};
Требования к переменным, на которые ссылаемся внутри анонимного класса Переменные, используемые внутри анонимного класса, должны быть effectively final (не изменяться после инициализации)
42. Расскажи что делает JIT компилятор #
JIT (Just-In-Time) компилятор преобразует байткод в машинный код для особо “горячих” (часто вызывающихся) частей кода во время выполнения программы для увеличения производительности
43. Расскажи про прогрев JVM #
Прогрев JVM - это оптимизация работы приложения в первые минуты его запуска. JIT анализирует исполняемый код и применяет оптимизации, такие как инлайнинг или устранение лишних проверок, escape-анализ (проверка на локальные объекты метода с возможностью размещать их в стеке, а не в куче)
https://docs.oracle.com/en/java/javase/25/vm/java-virtual-machine-guide.pdf
44. break vs continue в цикле #
break - выход из цикла continue - немедленный переход к следующей итерации
45. Что такое аннотация? Зачем нужна? Как создать свою аннотацию? #
Аннотация - это механизм пометки классов, методов и полей дополнительной информацией для компилятора, инструментов разработки и фреймворков
Основные аннотации в Java
| Аннотация | Описание |
|---|---|
@Override | Проверяет, что метод переопределяет метод суперкласса. |
@Deprecated | Отмечает метод/класс устаревшим, чтобы не использовать его в будущем. |
@SuppressWarnings | Подавляет определенные предупреждения компилятора. |
@FunctionalInterface | Показывает, что интерфейс является функциональным (с одним абстрактным методом). |
@SafeVarargs | Подавляет предупреждения о небезопасных операциях с аргументами переменной длины (varargs). |
@Native | Используется для констант, предназначенных для взаимодействия с нативным кодом. |
Метаданные аннотаций (Retention, Target)
Когда мы создаем свою аннотацию, важно понимать, как она будет использоваться. Это задается с помощью мета-аннотаций:
| Аннотация | Описание |
|---|---|
@Retention | Определяет, на каком этапе жизненного цикла аннотация доступна (SOURCE, CLASS, RUNTIME). |
@Target | Указывает, к чему можно применять аннотацию (методы, поля, классы и т. д.). |
@Documented | Включает аннотацию в Javadoc. |
@Inherited | Наследуется ли аннотация подклассами. |
@Repeatable | Позволяет применять одну и ту же аннотацию несколько раз. |
Как создать свою аннотацию?
import java.lang.annotation.*;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@interface MyAnnotation {
String value();
int count() default 1;
}
class Example {
@MyAnnotation(value = "Hello", count = 3)
public void test() {
System.out.println("Метод с аннотацией");
}
}
Чтение аннотации с помощью рефлексии
import java.lang.reflect.Method;
public class Main {
public static void main(String[] args) throws Exception {
Method method = Example.class.getMethod("test");
MyAnnotation annotation = method.getAnnotation(MyAnnotation.class);
System.out.println("value: " + annotation.value()); // "Hello"
System.out.println("count: " + annotation.count()); // 3
}
}
Где используются аннотации в реальных проектах? Lombok, JUnit, Spring
46. Переопределение и перегрузка методов #
Переопределение метода - это замена реализации метода класса-родителя в классе-наследнике. Правила
- метод должен иметь точно такое же имя, тип возвращаемого значения и аргументы.;
- метод в родительском классе не должен быть private;
- должен происходить в наследуемом классе;
- аннотация
@Overrideрекомендуется (не обязательна, но помогает избежать ошибок).
Перегрузка метода - это создание в классе нескольких методов с одним именем, но различными сигнатурами. Правила:
- имена методов одинаковые;
- различие - в количестве, типах или порядке аргументов (любая комбинация этих способов);
- возвращаемый тип может быть любым, но не используется для различия перегрузки.
47. ClassLoader в Java #
ClassLoader (загрузчик классов) - это специальный компонент JVM, предназначенный для загрузки классов в память во время выполнения программы. Загружает классы, соблюдая иерархию и принцип делегирования.
Иерархия загрузчиков:
- Bootstrap - загружает базовые классы (
java.lang.*,java.util.*) - Platform (Extension до Java 9) - загружает модули платформы
- Application/System - загружает классы из classpath
- Custom - зависит от реализации
Принцип делегирования - перед тем как загрузить класс, загрузчик обращается в вышестоящему по иерархии и спрашивает, не загрузил ли он уже такой класс, чтобы не загружать класс дважды.
48. В чем разница сравнений по equals и "=="? #
Оператор == сравнивает ссылки на объекты.
Метод equals() сравнивает объекты по содержимому, если правильно переопределён, потому что по умолчанию (наследуется от Object) реализация метода сводится к
public boolean equals(Object obj) {
return (this == obj);
}