- Модификаторы доступа - Access Modifiers
- Ключевые слова
- Final/finally/finalize
- Final: ограничения
- Static: применение
- Память, сборщик мусора - Memory Management, Garbage Collection
- Строки и пул строк(Pool string)
- Каллизия (Call-by-value и Call-by-reference)
- Методы класса Object
- Базовый синтаксис - Basic Syntax
- Интерфейсы - Interface
- Методы
- Классы
- Множественное наследование - Multiple Inheritance
-
Примитивные типы данных - это базовые типы, которые хранят непосредственные значения. Они занимают фиксированный объем памяти и не имеют методов или свойств.
-
Ссылочные типы данных - это типы, которые хранят ссылку на объект в памяти (в куче). Они позволяют работать с более сложными структурами данных, такими как классы, массивы, строки и интерфейсы.
| Тип | Категория | Размер (бит) | Диапазон/Описание |
|---|---|---|---|
| byte | Примитивный | 8 | -128 до 127 |
| short | Примитивный | 16 | -32768 до 32767 |
| int | Примитивный | 32 | -2^31 до 2^31-1 |
| long | Примитивный | 64 | -2^63 до 2^63-1 |
| float | Примитивный | 32 | Число с плавающей точкой |
| double | Примитивный | 64 | Число с плавающей точкой |
| char | Примитивный | 16 | Символ Unicode |
| boolean | Примитивный | - | true или false |
| String | Ссылочный | - | Последовательность символов |
| Классы | Ссылочный | - | Пользовательские типы |
| Массивы | Ссылочный | - | Коллекции элементов одного типа |
| Интерфейсы | Ссылочный | - | Абстрактные типы |
- Занимают фиксированный объем памяти.
- Не имеют методов и свойств.
- Копируются по значению: при передаче переменной создается новая копия значения.
- Пример использования:
int number = 10;
float pi = 3.14f;
char symbol = 'A';
boolean isTrue = true;- Хранят ссылку на объект в куче (heap).
- Объекты могут быть изменены после создания.
- Копируются по ссылке: две переменные могут ссылаться на один и тот же объект.
- Пример использования:
String message = "Hello, World!";
int[] numbers = {1, 2, 3, 4, 5};
List<String> list = new ArrayList<>();
list.add("Java");| Характеристика | Примитивные типы | Ссылочные типы |
|---|---|---|
| Хранение | Значение хранится напрямую | Хранится ссылка на объект |
| Размер | Фиксированный | Может варьироваться |
| Методы и свойства | Отсутствуют | Наличие методов и свойств |
| Копирование | По значению | По ссылке |
| Пример | int, float, boolean | String, массивы, классы |
🔄 К содержанию - главы
🔼 К содержанию
Мутабельные классы — это классы, объекты которых можно изменять после их создания. То есть состояние объекта может меняться через методы класса.
- Эффективное использование памяти, так как объект можно переиспользовать.
- Подходит для сценариев, где требуется частое изменение данных.
- Может привести к ошибкам, если объект используется несколькими потоками одновременно.
- Сложнее использовать в многопоточных приложениях.
// Класс StringBuilder является мутабельным
StringBuilder sb = new StringBuilder("Hello");
sb.append(" World!"); // Изменяет исходный объект
System.out.println(sb); // Вывод: Hello World!| Класс | Описание |
|---|---|
StringBuilder |
Класс для создания и изменения строк. Позволяет добавлять, удалять и изменять символы без создания нового объекта. |
ArrayList |
Динамический массив, который позволяет изменять размер коллекции и элементы внутри нее. |
HashMap |
Коллекция, хранящая пары ключ-значение. Ключи и значения могут быть изменены после создания объекта. |
HashSet |
Коллекция, хранящая уникальные элементы. Элементы можно добавлять, удалять или заменять. |
LinkedList |
Двусвязный список, поддерживающий динамическое изменение элементов и их порядка. |
Vector |
Устаревший аналог ArrayList, но с синхронизированными методами. Разрешает изменения содержимого. |
Stack |
Реализация стека на основе Vector. Поддерживает операции добавления и удаления элементов. |
Properties |
Подкласс Hashtable, используемый для работы с набором свойств. Может быть изменен во время выполнения. |
GregorianCalendar |
Класс для представления календарной даты и времени. Позволяет изменять поля даты и времени. |
DateFormat |
Абстрактный класс для форматирования и анализа дат. Некоторые реализации (например, SimpleDateFormat) мутабельны. |
AtomicInteger |
Класс для работы с целыми числами с поддержкой атомарных операций. Его значение может быть изменено. |
AtomicLong |
Аналогично AtomicInteger, но для длинных чисел. Значение объекта может меняться. |
ThreadLocalRandom |
Генератор случайных чисел, который может изменять свое внутреннее состояние при каждом вызове методов. |
Иммутабельные классы — это классы, объекты которых нельзя изменить после их создания. Любое изменение создает новый объект.
- Безопасность в многопоточных средах, так как объекты неизменяемы.
- Упрощение логики программы, так как состояние объекта известно заранее.
- Защита от несанкционированного изменения данных.
- Может потреблять больше памяти, так как при каждом изменении создается новый объект.
- Меньшая производительность при частых изменениях.
// Класс String является иммутабельным
String str = "Hello";
str += " World!"; // Создает новый объект
System.out.println(str); // Вывод: Hello World!| Класс | Описание |
|---|---|
String |
Класс для представления неизменяемых строк. Любая операция над строкой создает новый объект. |
Integer |
Обертка над примитивным типом int. Значение объекта не может быть изменено после создания. |
Long |
Обертка над примитивным типом long. Имеет фиксированное значение, которое нельзя изменить. |
Double |
Обертка над примитивным типом double. После инициализации значение остается неизменным. |
Float |
Обертка над примитивным типом float. Является иммутабельной оболочкой для чисел с плавающей точкой. |
Character |
Обертка над примитивным типом char. Значение символа не может быть изменено. |
Boolean |
Обертка над примитивным типом boolean. Состояние объекта (true/false) фиксировано. |
BigDecimal |
Класс для работы с десятичными числами высокой точности. Все операции создают новые объекты. |
BigInteger |
Класс для работы с целыми числами произвольной длины. Неизменяемость гарантирует безопасность данных. |
UUID |
Класс для уникальных идентификаторов. После создания UUID его значение остается постоянным. |
Enum |
Все перечисления (enum) в Java являются иммутабельными по умолчанию. |
ImmutableList |
Коллекция из библиотеки Guava или других фреймворков, которая не позволяет модификацию содержимого. |
ImmutableMap |
Иммутабельная реализация словаря, где пары ключ-значение остаются неизменными после создания. |
ImmutableSet |
Иммутабельная коллекция множеств, которая запрещает добавление, удаление или изменение элементов. |
| Характеристика | Мутабельные классы | Иммутабельные классы |
|---|---|---|
| Изменяемость | Объект можно изменять | Объект нельзя изменять |
| Память | Более эффективное использование | Может потреблять больше памяти |
| Безопасность потоков | Требует дополнительной синхронизации | Безопасны для многопоточности |
| Примеры | StringBuilder, ArrayList |
String, Integer |
🔄 К содержанию - главы
🔼 К содержанию
Основные принципы ООП:
ООП (Объектно-Ориентированное Программирование) — это подход к программированию, в котором программа строится как набор объектов, каждый из которых имеет свои данные (свойства) и функции (методы). Эти объекты могут взаимодействовать друг с другом, обмениваться информацией и выполнять задачи.
Функциональное программирование
(Функциональное программирование — это стиль программирования, в котором основное внимание уделяется вычислениям через функции, а не изменению состояния или данных. В этом подходе функции являются «первоклассными объектами», то есть их можно передавать как аргументы, возвращать из других функций и использовать без изменения их состояния.
Основные принципы ФП:
Чистые функции — функции, которые всегда возвращают один и тот же результат для одинаковых входных данных и не изменяют состояние программы.
Отсутствие побочных эффектов — функции не изменяют внешние данные или состояние программы (например, глобальные переменные).
Функции высшего порядка — функции, которые могут принимать другие функции в качестве аргументов или возвращать их.
⭐Инкапсуляция - сокрытие реализации.
Инкапсуляция подразумевает то, что мы скрываем какие-то свойства объекта и предоставляем к ним доступ в Java с помощью методов getter и setter, а также модификаторов доступа.
Вы нажимаете на кнопку зажигания, и автомобиль заводится. Вам не нужно знать, как именно работает двигатель внутри (процесс горения топлива, работа цилиндров и т.д.). Вся сложная реализация скрыта, а вы взаимодействуете только с простым интерфейсом — кнопкой.
Реализация: модификаторы доступа + геттеры/сеттеры.
⭐Наследование - создание новой сущности на базе уже существующей.
Наследование. То есть то, что класс может наследовать поведение и поля другого класса родительского.
Все автомобили имеют общие характеристики, такие как колеса, двигатель и руль. На их основе можно создать более специализированные типы:
Спортивный автомобиль (SportsCar) наследует от обычного автомобиля (Car) и добавляет уникальные особенности, например, увеличенную мощность или спортивный режим.
Грузовик (Truck) также наследует от автомобиля, но добавляет возможность перевозить грузы.
Реализация: extends + переопределение.
⭐Полиморфизм - возможность иметь разные формы для одной и той же сущности.
Полиморфизм. Один метод множества реализаций в Java с помощью переопределения и перегрузки.То есть один метод может быть реализован по-разному, в зависимости от того, от кого он вызывается, либо какие параметры в него передаются
У вас есть один пульт с кнопкой "Включить". В зависимости от того, на какое устройство вы его наведете, происходит разное действие:
- Телевизор → включается экран, запускается программа
- Кондиционер → запускается compressor, начинается охлаждение
- Музыкальный центр → включается усилитель, начинается воспроизведение
Одна команда "включить" - много разных реализаций.
Реализация: - Перегрузка (статический полиморфизм): Несколько методов с одним именем, но разными параметрами в одном классе. Компилятор сам выбирает, какой вызвать.
- Переопределение (динамический полиморфизм): Потомок изменяет логику метода, унаследованного от родителя. Какой метод будет вызван, решается во время выполнения программы.
- Реализация: переопределение через @Override и вызов через ссылку на класс-родитель/интерфейс.
⭐Абстракция - набор общих характеристик.
Абстракция. Мы абстрактно выделяем какие-то главные свойства, а неглавные не выделяем.
Автомобиль — это абстрактная концепция, которая объединяет общие свойства всех машин: они имеют колеса, двигатель, руль и могут ехать. Конкретные модели (например, Toyota Camry или Tesla Model 3) добавляют свои уникальные детали, но все они основаны на этой общей абстракции.
Таким образом, абстракция позволяет нам думать об автомобиле как о единой сущности, не углубляясь в детали каждой конкретной модели.
Реализация: interface/abstract + разная реализация.
Посылка сообщений - форма связи, взаимодействия между сущностями.
Переиспользование- все что перечислено выше работает на повторное использование кода.
- Класс: Это шаблон или blueprint, который определяет структуру и поведение объектов. Он описывает, какие данные (свойства) и действия (методы) будут доступны для объектов этого типа.
- Объект: Это экземпляр класса. Объект представляет собой конкретную сущность, созданную на основе класса. У каждого объекта есть свои уникальные значения свойств, но все они следуют общей структуре, заданной классом.
- Инкапсуляция — это механизм скрытия внутренней реализации объекта и предоставления доступа к его функционалу только через публичный интерфейс.
- Основные методы реализации инкапсуляции:
- Модификаторы доступа (public, private, protected, default).
- Скрытие данных через ограничение прямого доступа к переменным.
- Методы-геттеры и сеттеры для безопасного управления внутренними данными.
- Наследование позволяет одному классу (дочернему) получить все свойства и методы другого класса (родительского).
- Основные аспекты реализации наследования.
- Ключевое слово extends (для наследования класса).
- Повторное использование кода, что упрощает разработку.
- Расширение функциональности через добавление новых или изменение существующих методов.
- Полиморфизм означает "многозначность" и позволяет использовать один интерфейс для различных типов данных.
- Ключевые моменты
- Перегрузка методов:
- Позволяет иметь несколько методов с одним именем, но с разными параметрами.
- Ключевые моменты:
- Статический полиморфизм, который определяется на этапе компиляции.
- Удобство для различных сценариев, например, сложение чисел разных типов.
- Переопределение методов:
- Позволяет дочерним классам изменить поведение метода родительского класса.
- Ключевые моменты:
- Динамический полиморфизм, который определяется на этапе выполнения.
- Использование аннотации @Override, чтобы явно указать переопределение.объектов.
- Абстракция — это процесс выделения главных характеристик объекта, игнорируя второстепенные детали.
Основные методы реализации абстракции:
- Абстрактные классы (с возможностью включения как абстрактных, так и конкретных методов).
- Интерфейсы, которые определяют только сигнатуру методов без их реализации.
- Модульность: Код становится более организованным и разделенным на логические блоки.
- Расширяемость: Программа легко адаптируется к изменениям требований.
- Безопасность: Защищает данные и предотвращает несанкционированное изменение внутренней реализации.
- Читаемость: Упрощает понимание кода благодаря четкой структуре и разделению ответственности.
🔄 К содержанию - главы
🔼 К содержанию
- Определение: Переопределение метода происходит, когда дочерний класс предоставляет свою реализацию метода, который уже определен в родительском классе.
- Цель: Позволяет изменить поведение метода для конкретного типа данных или класса.
- Правила:
- Метод в дочернем классе должен иметь ту же сигнатуру (имя, типы параметров) и уровень доступа, что и в родительском классе.
- Аннотация
@Overrideиспользуется для явного указания переопределения метода (рекомендуется для избежания ошибок).
- Пример: Если в родительском классе есть метод
display(), то дочерний класс может переопределить его для вывода другой информации.
- Определение: Перегрузка метода означает создание нескольких методов с одним и тем же именем, но с разными параметрами (количеством, типами или порядком).
- Цель: Позволяет использовать одинаковое имя метода для выполнения разных операций в зависимости от входных параметров.
- Правила:
- Сигнатуры методов должны различаться (разные типы или количество параметров).
- Перегрузка может происходить как внутри одного класса, так и между родительским и дочерним классами.
- Пример: Метод
calculate(int a, int b)может быть перегружен какcalculate(double a, double b).
Сравнительная таблица: Переопределение vs Перегрузка
| Критерий | Переопределение (Override) | Перегрузка (Overload) |
|---|---|---|
| Определение | Изменение реализации метода в дочернем классе, сохраняя ту же сигнатуру. | Создание нескольких методов с одним и тем же именем, но разными параметрами. |
| Цель | Изменить поведение метода для конкретного типа данных или класса. | Предоставить разные варианты использования одного имени метода. |
| Сигнатура метода | Должна быть одинаковой (имя и типы параметров). | Должна различаться (количество, типы или порядок параметров). |
| Уровень доступа | Уровень доступа в дочернем классе не может быть более строгим. | Не влияет на перегрузку. |
| Аннотация | Используется аннотация @Override для явного указания переопределения. |
Аннотация не требуется. |
| Место применения | Только между родительским и дочерним классами. | В пределах одного класса или между классами. |
| Возвращаемый тип | Должен совпадать с типом возвращаемого значения родительского метода или быть его подтипом (covariant return type). | Может быть любым, так как это не влияет на перегрузку. |
| Пример | class Parent { void display() {} }class Child extends Parent { @Override void display() {} } |
void calculate(int a, int b) {}void calculate(double a, double b) {} |
🔄 К содержанию - главы
🔼 К содержанию
- Определение: Абстрактный класс — это класс, который не предназначен для создания экземпляров напрямую. Он содержит абстрактные методы (без реализации) и/или обычные методы (с реализацией).
- Использование: Используется, когда нужно предоставить общую базовую функциональность для подклассов, а также задать контракт для обязательной реализации некоторых методов.
- Особенности:
- Может содержать как абстрактные, так и конкретные методы.
- Поддерживает наследование (одиночное наследование).
- Может иметь состояния (поля), которые могут быть использованы подклассами.
- Пример: Базовый класс
Vehicleможет быть абстрактным, а подклассыCarиTruckбудут реализовывать специфические методы.
Мы можем создать объект абстрактного класса?
Нет
-
Определение: Интерфейс представляет собой полностью абстрактный тип, содержащий только объявления методов (до Java 8) или методы по умолчанию и статические методы (начиная с Java 8).
Методы по умолчанию:
Методы по умолчанию (default methods) появились в Java 8. Они позволяют добавлять реализацию методов в интерфейс без необходимости изменять классы, которые уже этот интерфейс реализуют. Такие методы определяются с помощью ключевого слова "default". Это позволяет добавлять новые методы в интерфейсы, сохраняя обратную совместимость.
Статические методы:
Статические методы в интерфейсах также появились в Java 8. Эти методы принадлежат самому интерфейсу, а не его экземплярам. Они определяются с использованием ключевого слова "static". Такие методы можно вызывать напрямую через имя интерфейса, и они используются для предоставления утилитарной функциональности, связанной с интерфейсом. -
Использование: Используется для определения контракта, который должны реализовать классы. Это позволяет обеспечить полиморфизм без наследования.
-
Особенности:
- Начиная с Java 8, интерфейсы могут содержать методы по умолчанию (
default) и статические методы. - Класс может реализовывать несколько интерфейсов (множественная "реализация").
- Не может содержать состояния (поля), за исключением
final staticпеременных.
- Начиная с Java 8, интерфейсы могут содержать методы по умолчанию (
-
Пример: Интерфейс
Runnableопределяет методrun(), который должен быть реализован классами для выполнения потока.
| Характеристика | Абстрактный класс | Интерфейс |
|---|---|---|
| Наследование | Одиночное наследование (extends) |
Множественная реализация (implements) |
| Поля/Состояние | Может иметь обычные и статические поля | Все поля автоматически public static final (константы), даже если модификаторы не указаны явно |
| Методы | Может иметь поля любого типа: обычные, статические, final, с любыми модификаторами доступа | abstract, default, static, private |
| Конструкторы | Может иметь конструкторы | Не может иметь конструкторов |
| Когда использовать | Когда требуется частичная реализация с возможностью переопределения в наследниках | Когда нужен только контракт (спецификация поведения) |
| Применение | Основные классы и структуры, требующие общего функционала | API, плагины, колбэки, стратегии (где важна гибкость и совместимость) |
| Связанность | Сильная связанность (наследование) | Слабая связанность (разные реализации). |
🔄 К содержанию - главы
🔼 К содержанию
Модификаторы доступа в Java определяют, какой код может получить доступ к классам, методам, полям или конструкторам.
| Модификатор доступа | Уровень доступа |
|---|---|
| private | Видно только внутри класса. |
| default | Видно только внутри пакета. |
| protected | Видно внутри класса + у наследников (extends). |
| public | Видно всем, даже тебе🤭 |
-
private:
- Доступен только внутри того же класса.
- Используется для скрытия данных (инкапсуляция).
-
default (без модификатора):
- Доступен только внутри пакета.
- Не требует явного указания.
-
protected:
- Доступен внутри пакета и во всех подклассах вне пакета.
- Часто используется для методов, которые должны быть доступны дочерним классам.
-
public:
- Доступен из любого места в программе.
- Используется для открытых API и основных точек входа.
🔄 К содержанию - главы
🔼 К содержанию
-
На уровне класса
Класс не может быть унаследован (запрещает наследование). -
На уровне метода
Метод нельзя переопределить в подклассах. -
На уровне переменной
Значение переменной нельзя изменить после инициализации (константа или неизменяемая ссылка). -
На уровне параметра метода
Значение параметра нельзя изменить внутри метода.
-
На уровне класса
Поля и методы принадлежат самому классу, а не объектам.
Можно обращаться без создания экземпляра. -
На уровне метода
Метод может вызываться без объекта.
Внутри метода нельзя использоватьthisиsuper. -
На уровне переменной
Переменная общая для всех объектов класса (одно значение на весь класс). -
На уровне вложенного класса
Статический вложенный класс не связан с экземпляром внешнего класса.
-
На уровне конструктора
Вызывает конструктор родительского класса. -
На уровне метода
Обращение к методу родительского класса (даже если он переопределён). -
На уровне поля
Доступ к полю родительского класса, если оно перекрыто в наследнике.
🔄 К содержанию - главы
🔼 К содержанию
| Ключевое слово | Описание |
|---|---|
final |
- Класс: Запрещает наследование от этого класса. |
| - Метод: Запрещает переопределение метода в подклассах. |
|
| - Переменная: Значение переменной становится неизменяемым после инициализации. | |
finally |
Блок finally используется вместе с блоком try-catch для выполнения важного кода, который должен выполняться независимо от того, произошло исключение или нет. Пример: закрытие файлов, соединений с базами данных. |
finalize |
Метод finalize() вызывается перед сборкой мусора для выполнения очистки ресурсов. Не рекомендуется использовать, так как его поведение не гарантировано, и он был объявлен устаревшим начиная с Java 9. |
- Класс: Запрещает наследование от этого класса.
- Метод: Запрещает переопределение метода в подклассах.
- Переменная: Значение переменной становится неизменяемым после инициализации.
- Блок
finallyиспользуется вместе с блокомtry-catchдля выполнения важного кода, который должен выполняться независимо от того, произошло исключение или нет. - Пример: закрытие файлов, соединений с базами данных.
- Метод
finalize()вызывается перед сборкой мусора для выполнения очистки ресурсов. - Не рекомендуется использовать, так как его поведение не гарантировано, и он был объявлен устаревшим начиная с Java 9.
Использование ключевого слова final накладывает следующие ограничения:
-
Final классы:
- Нельзя создать подклассы от
finalкласса. - Полезно для классов, которые предоставляют финальную реализацию и не должны изменяться.
- Нельзя создать подклассы от
-
Final методы:
- Нельзя переопределить
finalметод в подклассах. - Полезно для методов, которые обеспечивают критически важную функциональность и не должны быть изменены.
- Нельзя переопределить
-
Final переменные:
- Значение
finalпеременной должно быть присвоено один раз и не может быть изменено. - Для примитивных типов это означает фиксированное значение.
- Для ссылочных типов это означает, что ссылка не может быть изменена, но содержимое объекта может меняться, если сам объект не является неизменяемым.
- Значение
🔄 К содержанию - главы
🔼 К содержанию
| Ключевое слово | Описание |
|---|---|
static |
Обозначает, что переменная, метод или блок принадлежит классу, а не экземпляру. Это позволяет обращаться к ним без создания объекта. |
final |
Используется для обозначения констант (неизменяемых значений), окончательных классов (которые нельзя наследовать) или методов (которые нельзя переопределить). |
abstract |
Помечает класс или метод как абстрактный. Абстрактный класс не может быть создан напрямую, а абстрактный метод должен быть реализован в подклассах. |
private |
Указывает, что доступ к методу или переменной возможен только внутри того же класса. Это ограничивает видимость элементов класса. |
protected |
Разрешает доступ к методу или переменной внутри того же пакета и всем подклассам вне пакета. |
public |
Делает метод или переменную доступными из любого места программы. Это наиболее открытый уровень доступа. |
this |
Ссылается на текущий экземпляр класса. Используется для доступа к переменным или методам того же объекта. |
super |
Ссылается на родительский класс. Используется для вызова методов или доступа к переменным родителя. |
synchronized |
Используется для обеспечения потокобезопасности. Метод или блок кода помеченный этим словом может выполняться только одним потоком одновременно. |
transient |
Указывает, что поле не должно сериализоваться при сохранении состояния объекта. |
volatile |
Обозначает, что значение переменной может изменяться разными потоками, и все изменения должны быть видны другим потокам без дополнительной синхронизации. |
native |
Помечает метод, который реализован на другом языке программирования (например, C или C++). |
strictfp |
Гарантирует точность вычислений с плавающей запятой, заставляя JVM использовать строгие правила IEEE 754. |
interface |
Обозначает спецификацию поведения, которую должны реализовать классы. Интерфейс определяет контракт без конкретной реализации. |
enum |
Используется для создания ограниченного набора констант. Например, дни недели или цвета. |
package |
Группирует связанные классы и интерфейсы в одну единицу. Это помогает организовать код и избежать конфликтов имен. |
import |
Позволяет использовать классы из других пакетов без необходимости указывать полное имя класса. |
throws |
Указывает, что метод может выбросить исключение. Это предупреждает вызывающий код о возможных проблемах. |
try |
Используется для блока кода, где может возникнуть исключение. |
catch |
Обрабатывает исключения, возникающие в блоке try. |
finally |
Выполняется всегда после блока try-catch, независимо от того, было ли выброшено исключение. |
throw |
Прерывает выполнение метода и передает управление обработчику исключений. |
assert |
Проверяет условие во время выполнения программы. Если условие ложно, выбрасывается ошибка AssertionError. |
Ключевое слово static используется для создания членов класса, которые принадлежат самому классу, а не его экземплярам.
-
Static переменные:
- Общие для всех экземпляров класса.
- Хранят одно значение для всего класса.
- Пример: счетчик количества созданных объектов.
-
Static методы:
- Может быть вызван без создания экземпляра класса.
- Не имеет доступа к нестатическим полям и методам, так как они принадлежат конкретным экземплярам.
- Пример: методы класса
Math, такие какMath.sqrt().
-
Static блоки:
- Выполняются один раз при загрузке класса.
- Используются для инициализации статических переменных.
-
Static вложенные классы:
- Вложенный класс, который можно использовать без создания экземпляра внешнего класса.
- Полезно для группировки связанных классов.
🔄 К содержанию - главы
🔼 К содержанию
Условные операторы используются для выполнения различных блоков кода в зависимости от условия.
-
if:
- Выполняет блок кода, если условие истинно.
- Синтаксис:
if (условие) { // Код, который выполняется, если условие истинно }
-
if-else:
- Выполняет один блок кода, если условие истинно, и другой блок, если ложно.
- Синтаксис:
if (условие) { // Код, который выполняется, если условие истинно } else { // Код, который выполняется, если условие ложно }
-
if-else if-else:
- Позволяет проверить несколько условий последовательно.
- Синтаксис:
if (условие1) { // Код для условия1 } else if (условие2) { // Код для условия2 } else { // Код для остальных случаев }
-
switch:
- Используется для выбора одного из нескольких вариантов на основе значения выражения.
- Синтаксис:
switch (выражение) { case значение1: // Код для значения1 break; case значение2: // Код для значения2 break; default: // Блок default выполняется, если значение выражения не совпало ни с одним из case. // Код для остальных случаев }
🔄 К содержанию - главы
🔼 К содержанию
-
Автоупаковка (Autoboxing):
- Процесс автоматического преобразования примитивных типов данных (например,
int,double) в их обертки (например,Integer,Double). - Пример:
int primitive = 10; Integer wrapper = primitive; // Автоупаковка
- Процесс автоматического преобразования примитивных типов данных (например,
-
Распаковка (Unboxing):
- Процесс автоматического преобразования оберток обратно в примитивные типы.
- Пример:
Integer wrapper = 10; int primitive = wrapper; // Распаковка
-
Преимущества:
- Упрощает работу с коллекциями, так как они принимают только объекты, а не примитивные типы.
- Сокращает необходимость ручного преобразования между примитивами и их обертками.
-
Ограничения:
- Может привести к непредвиденным ошибкам при работе с
nullзначениями, например:Integer value = null; int result = value; // NullPointerException
- Может привести к непредвиденным ошибкам при работе с
🔄 К содержанию - главы
🔼 К содержанию
Циклы используются для повторного выполнения блока кода несколько раз.
-
for:
- Используется, когда известно количество итераций.
- Синтаксис:
for (инициализация; условие; обновление) { // Код для выполнения }
- Пример:
for (int i = 0; i < 5; i++) { System.out.println(i); }
-
while:
- Выполняет блок кода, пока условие истинно.
- Синтаксис:
while (условие) { // Код для выполнения }
- Пример:
int i = 0; while (i < 5) { System.out.println(i); i++; }
-
do-while:
- Похож на
while, но гарантирует выполнение блока кода хотя бы один раз. - Синтаксис:
do { // Код для выполнения } while (условие);
- Пример:
int i = 0; do { System.out.println(i); i++; } while (i < 5);
- Похож на
-
for-each:
- Упрощенный вариант цикла
forдля перебора элементов коллекций или массивов. - Синтаксис:
for (тип элемента : коллекция) { // Код для выполнения }
- Пример:
int[] numbers = {1, 2, 3, 4, 5}; for (int number : numbers) { System.out.println(number); }
- Упрощенный вариант цикла
🔄 К содержанию - главы
🔼 К содержанию
Исключение (Exception) — это как светофор, который резко переключился на красный, когда ты едешь по программе.
- Это непредвиденная проблема или ошибка, которая случается, пока программа работает.
- Например:
- Ты просишь программу открыть файл, а его нет.
- Ты пытаешься поделить число на ноль (математика этого не позволяет).
- Программа пытается подключиться к Интернету, а связь оборвалась.
Когда такое происходит, программа прерывает свою обычную работу и кричит (выбрасывает исключение): "Эй! У меня тут проблема!"
Используем исключения, чтобы программа была непотопляемой и вежливой.
-
Программа не "умирает" (Непрерывность):
- Если ошибка происходит, и ты её не обрабатываешь, программа просто вылетает (аварийно завершается).
- Исключения позволяют программе поймать проблему, как ловит сеть, и не упасть.
-
Вежливое сообщение (Обратная связь):
- Вместо того чтобы просто погаснуть, программа может вежливо сообщить пользователю: "Извините, вы ввели не число" или "Не удалось сохранить данные, попробуйте позже".
-
Разделение ответственности (Чистота кода):
- Ты пишешь "нормальный" код, который делает свою работу (например, загружает данные).
- Отдельно ты пишешь код, который включается только если что-то пошло не так (например, если загрузить данные не удалось). Это делает основной план действий очень чистым и понятным.
Итог: Исключения — это план "Б" для твоей программы. Они позволяют предвидеть неприятности и подготовить для них спасательные круги, чтобы программа могла продолжить работу или корректно завершиться.
🔄 К содержанию - главы
🔼 К содержанию
В Java все исключения организованы в иерархическую структуру, которая начинается с класса Throwable. От него наследуются два основных подкласса: Error и Exception.
-
Throwable:
- Корневой класс для всех ошибок и исключений.
- Позволяет обрабатывать как программные ошибки (
Exception), так и системные (Error).
-
Error:
- Представляет серьезные проблемы, которые обычно невозможно обработать программой.
- Примеры:
OutOfMemoryError: Возникает, когда JVM не может выделить больше памяти.StackOverflowError: Происходит при переполнении стека вызовов, обычно из-за бесконечной рекурсии.VirtualMachineError: Указывает на серьезные сбои в виртуальной машине Java.NoClassDefFoundError: JVM не может найти определенный класс.UnsatisfiedLinkError: Ошибка связывания нативных библиотек.
-
Exception:
- Представляет исключительные ситуации, которые можно обработать в программе.
- Делится на две категории:
Checked Exceptions:
- Исключения, которые обязательно должны быть обработаны или объявлены в сигнатуре метода.
- Примеры:
IOException: Ошибка ввода-вывода, например, при чтении файла.SQLException: Ошибка при работе с базами данных.FileNotFoundException: Файл не найден.ClassNotFoundException: Класс не найден.ParseException: Ошибка анализа данных, например, при разборе даты.InterruptedException: Поток был прерван.
Unchecked Exceptions (Runtime Exceptions):
- Исключения, которые не требуют обязательной обработки.
- Примеры:
NullPointerException: Попытка обращения к объекту черезnull.ArrayIndexOutOfBoundsException: Доступ к несуществующему индексу массива.ArithmeticException: Ошибка математической операции, например, деление на ноль.ClassCastException: Неправильное приведение типов.IllegalArgumentException: Некорректный аргумент метода.NumberFormatException: Ошибка преобразования строки в число.IllegalStateException: Неверное состояние объекта для вызова метода.
- Error: Серьезные системные сбои, обработка обычно невозможна. Например, нехватка памяти.
- Exception: Ошибки программы, которые можно и нужно обрабатывать. Например, неправильный ввод пользователя.
🔄 К содержанию - главы
🔼 К содержанию
Обработка исключений в Java осуществляется с помощью блоков try-catch-finally и оператора throw/throws.
-
try:
- Блок кода, который может выбросить исключение.
- Синтаксис:
try { // Код, который может выбросить исключение }
-
catch:
- Блок для обработки конкретного типа исключения.
- Можно использовать несколько блоков
catchдля разных типов исключений. - Синтаксис:
catch (ExceptionType e) { // Обработка исключения }
-
finally:
- Блок, который выполняется всегда, независимо от того, было ли выброшено исключение.
- Используется для освобождения ресурсов (например, закрытие файлов, соединений с базами данных).
- Синтаксис:
finally { // Код, который выполняется всегда }
-
throw:
- Оператор для явного выброса исключения.
- Синтаксис:
throw new ExceptionType("Сообщение об ошибке");
-
throws:
- Ключевое слово для указания, что метод может выбросить определенное исключение.
- Синтаксис:
public void someMethod() throws ExceptionType { // Код метода }
-
Пример полной конструкции:
try { // Код, который может выбросить исключение } catch (SpecificException e) { // Обработка конкретного исключения } catch (AnotherException e) { // Обработка другого исключения } finally { // Код, который выполняется всегда }
-
Автоматическое управление ресурсами (try-with-resources):
Для использования механизма try-with-resources в Java необходимо, чтобы объект, который вы хотите использовать в блоке try, реализовывал интерфейс AutoCloseable
Введено в Java 7 для автоматического закрытия ресурсов, таких как файлы или соединения с базами данных. Синтаксис:try (Resource resource = new Resource()) { // Код, который использует ресурс } catch (Exception e) { // Обработка исключения }
| Элемент / Ключевое слово | Назначение (Что делает?) | Место использования (Где используется?) | Главная задача |
|---|---|---|---|
try |
Определяет опасную зону — блок кода, который может вызвать ошибку. | Вокруг потенциально проблемного кода. | Изолировать код, где может произойти исключение, для последующей его обработки. |
catch |
Перехватывает и обрабатывает конкретный тип исключения, если оно было выброшено в блоке try. |
Сразу после блока try (может быть несколько). |
Реализовать логику восстановления, оповещения или записи ошибки. |
finally |
Определяет код, который обязательно выполнится в конце, независимо от того, было исключение или нет. | После try и всех catch блоков. |
Освобождение/закрытие ресурсов (файлов, соединений) для предотвращения утечек. |
throw |
Явно (принудительно) выбрасывает новое или существующее исключение из текущего места выполнения. | Внутри тела метода (как обычная инструкция). | Создать и отправить исключение, когда обнаружено недопустимое состояние. |
throws |
Декларирует (предупреждает) в сигнатуре метода, что этот метод может выбросить одно или несколько указанных проверяемых исключений. | В заголовке метода. | Обязать вызывающий код либо обработать это исключение, либо пробросить его дальше. |
try-with-resources |
Автоматически и безопасно закрывает ресурсы, объявленные в скобках try, после завершения работы. |
Вместо обычного try при работе с ресурсами, реализующими AutoCloseable. |
Обеспечить гарантированное освобождение ресурсов, делая ненужным явный блок finally для закрытия. |
🔄 К содержанию - главы
🔼 К содержанию
Stream API — это инструмент, введенный в Java 8, который позволяет обрабатывать коллекции данных в функциональном стиле. Он представляет собой последовательность элементов, над которыми можно выполнять различные операции, такие как фильтрация, преобразование и агрегирование. Stream API делает работу с данными более эффективной и компактной, позволяя писать код в декларативном стиле.
Основная идея Stream API заключается в том, чтобы отделить логику обработки данных от их хранения. Потоки не хранят данные, они лишь предоставляют возможность их обработки.
-
Поток (Stream)
Поток — это последовательность элементов, которая поддерживает операции обработки. Потоки создаются на основе существующих коллекций или массивов и не изменяют исходные данные. -
Операции над потоками
- Промежуточные операции: Возвращают новый поток и могут быть вызваны друг с другом. Примеры:
filter,map,sorted. - Терминальные операции: Завершают цепочку операций и производят результат или побочный эффект. Примеры:
collect,forEach,reduce.
- Промежуточные операции: Возвращают новый поток и могут быть вызваны друг с другом. Примеры:
-
Ленивое выполнение
Промежуточные операции выполняются лениво, то есть фактическая обработка начинается только при вызове терминальной операции. -
Параллельная обработка
Stream API поддерживает параллельную обработку данных через методparallelStream(), что может значительно ускорить вычисления для больших наборов данных.
- Функциональный стиль программирования: Упрощает сложные операции над данными, делая код более читаемым и понятным.
- Ленивое выполнение: Оптимизирует производительность за счет отложенного выполнения промежуточных операций.
- Параллельная обработка: Обеспечивает возможность использования нескольких потоков для обработки данных.
- Компактность: Сокращает объем кода по сравнению с традиционными циклами и условными конструкциями.
| Тип операции | Методы | Описание |
|---|---|---|
| Промежуточные | filter |
Отфильтровывает элементы, соответствующие заданному условию. |
map |
Преобразует каждый элемент потока с помощью заданной функции. | |
flatMap |
Преобразует каждый элемент потока в поток и объединяет все потоки. | |
peek |
Отладочная операция — позволяет "заглянуть" в элементы, не модифицируя их. | |
sorted |
Сортирует элементы потока. | |
distinct |
Удаляет дубликаты из потока. | |
limit |
Ограничивает количество элементов в потоке. | |
skip |
Пропускает указанное количество элементов в начале потока. | |
takeWhile |
Берёт элементы, пока условие истинно. | |
dropWhile |
Пропускает элементы, пока условие истинно, затем берёт оставшиеся. | |
| Терминальные | forEach |
Выполняет действие для каждого элемента потока. |
forEachOrdered |
Выполняет действие с сохранением порядка (для параллельных потоков). | |
collect |
Собирает результаты в коллекцию или другую структуру данных. | |
reduce |
Агрегирует элементы потока в одно значение (например, сумма или максимум). | |
count |
Возвращает количество элементов в потоке. | |
anyMatch, allMatch, noneMatch |
Проверяет, удовлетворяют ли элементы заданному условию. | |
findFirst, findAny |
Находит первый или любой элемент, удовлетворяющий условию. | |
toArray |
Преобразует поток в массив. | |
min, max |
Находит минимальный или максимальный элемент по заданному компаратору. |
-
Пример использования:
List<String> names = Arrays.asList("Alice", "Bob", "Charlie"); names.stream() .filter(name -> name.startsWith("A")) .map(String::toUpperCase) .forEach(System.out::println);
-
Преимущества:
- Упрощает работу с коллекциями.
- Поддерживает параллельную обработку данных
(parallelStream). - Позволяет писать более читаемый и компактный код.
🔄 К содержанию - главы
🔼 К содержанию
Лямбда-выражения — это механизм, позволяющий представлять анонимные функции в Java. Они были введены в язык программирования начиная с версии 8 и служат для передачи логики как параметра без необходимости создавать полноценные классы или анонимные внутренние классы.
Анонимные функции — это функции без имени, которые можно использовать для передачи логики в качестве аргумента или создания временных блоков кода.
Основная цель лямбда-выражений — упростить код, сделать его более компактным и читаемым, особенно при работе с функциональными интерфейсами и API потоков (Stream API).
-
Функциональные интерфейсы
Лямбда-выражения могут использоваться только с функциональными интерфейсами — интерфейсами, которые содержат ровно один абстрактный метод. Например,Runnable,Callable,Predicate,Consumerи другие. -
Типизация
Лямбда-выражения являются строго типизированными. Тип лямбды определяется контекстом, в котором она используется, обычно это функциональный интерфейс. -
Синтаксис
Структура лямбда-выражения состоит из списка параметров, разделенных запятой, стрелки->и тела выражения. Если тело выражения состоит из одного оператора, фигурные скобки можно опустить. -
Захват переменных
Лямбда-выражения могут использовать переменные из окружающего контекста (локальные переменные или поля класса). Однако локальные переменные должны быть effectively final (не изменяться после инициализации). -
Применение
- Лямбда-выражения широко используются для реализации функциональных интерфейсов.
- Они значительно упрощают работу с коллекциями через Stream API, позволяя выполнять операции фильтрации, преобразования и агрегирования данных.
- Сокращают необходимость создания анонимных классов, что делает код более лаконичным.
- Компактность: Лямбда-выражения позволяют записывать код короче, чем использование анонимных классов.
- Читаемость: Благодаря простому синтаксису, код становится легче восприниматься.
- Функциональный стиль программирования: Поддержка императивного подхода к решению задач через функциональные интерфейсы и Stream API.
| Термин | Описание |
|---|---|
| Функциональный интерфейс | Интерфейс с одним абстрактным методом, который может быть представлен лямбдой. |
| Effectively final | Переменная, которая не явно объявлена как final, но фактически не изменяется. |
| Stream API | API для обработки коллекций данных в функциональном стиле. |
| Захват переменных | Возможность использования внешних переменных внутри лямбда-выражения. |
| Анонимные классы | Предшественники лямбд для реализации одноразовых объектов. |
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5)
numbersforEach(n -> Systemoutprintln(n * 2))🔄 К содержанию - главы
🔼 К содержанию
Функциональный интерфейс — это специальный тип интерфейса в Java, который содержит ровно один абстрактный метод. Он служит основой для работы с лямбда-выражениями и методами ссылок, которые были добавлены в Java 8. Благодаря функциональным интерфейсам можно передавать логику (кусок кода) как параметр, что делает код более гибким и компактным.
Функциональные интерфейсы позволяют:
- Упростить код: Вместо создания целых классов или анонимных классов для реализации интерфейсов, можно использовать короткие лямбда-выражения.
- Стандартизировать операции: Они предоставляют готовые шаблоны для распространенных типов операций, таких как проверка условий, преобразование данных или выполнение действий.
В Java есть множество встроенных функциональных интерфейсов, каждый из которых решает определенную задачу:
| Интерфейс | Назначение | Пример использования |
|---|---|---|
Predicate<T> |
Проверяет условие и возвращает true или false. |
Проверка, является ли число четным: n -> n % 2 == 0 |
Function<T, R> |
Преобразует значение одного типа в другой. | Преобразование строки в число: str -> Integer.parseInt(str) |
Consumer<T> |
Выполняет действие с переданным параметром и ничего не возвращает. | Вывод текста в консоль: text -> System.out.println(text) |
Supplier<T> |
Возвращает значение без параметров. | Получение текущей даты: () -> new Date() |
BiFunction<T, U, R> |
Принимает два параметра разных типов и возвращает результат. | Сложение двух чисел: (a, b) -> a + b |
UnaryOperator<T> |
Принимает и возвращает значение одного типа (специализированный Function). |
Увеличение числа на 1: n -> n + 1 |
Когда вы используете лямбда-выражение, Java автоматически связывает его с соответствующим функциональным интерфейсом. Например:
- Если ваше лямбда-выражение представляет собой проверку условия (
n -> n > 0), оно будет связано с интерфейсомPredicate. - Если лямбда выполняет преобразование (
str -> str.toUpperCase()), она будет связана с интерфейсомFunction.
- Упрощение кода: Лямбда-выражения делают код короче и понятнее.
- Гибкость: Можно легко передавать логику между методами и классами.
- Стандартные контракты: Использование стандартных интерфейсов уменьшает необходимость создавать свои собственные.
🔄 К содержанию - главы 🔼 К содержанию
| Интерфейс/Класс | Описание | Реализации / Примечания |
|---|---|---|
Collection |
Корневой интерфейс для всех коллекций (кроме Map). |
Включает методы общего назначения: add(), remove(), size(). |
List |
Упорядоченная коллекция с возможностью дублирования элементов. | |
- ArrayList |
Базируется на массиве, быстрый доступ по индексу. | Не потокобезопасен. |
- LinkedList |
Базируется на двусвязном списке, эффективен для вставки/удаления. | Поддерживает работу как Deque. |
- Vector |
Синхронизированная версия ArrayList. |
Устаревшая, менее эффективна. |
- Stack |
Наследник Vector, реализует стек (LIFO). |
Устаревшая, рекомендуется использовать Deque. |
Set |
Коллекция без дубликатов, не гарантирует порядок хранения. | |
- HashSet |
Базируется на хеш-таблице, не сохраняет порядок. | Потоки могут вызывать неопределённое поведение. |
- LinkedHashSet |
Сохраняет порядок вставки элементов. | Использует связанный список внутри HashSet. |
- TreeSet |
Автоматически сортирует элементы по их натуральному порядку или компаратору. | Реализовано на основе красно-черного дерева. |
Queue |
Коллекция для очередей, обычно работает по принципу FIFO (First In, First Out). | |
- PriorityQueue |
Хранит элементы в порядке их приоритета. | Не поддерживает null и не гарантирует потокобезопасность. |
- LinkedList |
Может использоваться как очередь. | Поддерживает работу как Deque. |
Deque |
Двусторонняя очередь, позволяет добавление/удаление с обоих концов. | |
- ArrayDeque |
Более эффективная реализация, основанная на массиве. | Рекомендуется вместо LinkedList. |
- LinkedList |
Также может использоваться как Deque. |
Менее эффективен, чем ArrayDeque. |
Map |
Отображение ключ-значение, где ключи уникальны. | |
- HashMap |
Базируется на хеш-таблице, не гарантирует порядок. | Не потокобезопасен. |
- LinkedHashMap |
Сохраняет порядок вставки пар ключ-значение. | Использует связанный список внутри HashMap. |
- TreeMap |
Автоматически сортирует ключи по их натуральному порядку или компаратору. | Реализовано на основе красно-чёрного дерева. |
- EnumMap |
Специализированный Map, где ключи ограничены набором значений enum. |
Очень эффективен для работы с перечислениями. |
| Сортированные коллекции | Расширения для автоматической сортировки. | |
- SortedSet |
Расширение Set, автоматически сортирует элементы. |
Реализация: TreeSet. |
- NavigableSet |
Расширение SortedSet, предоставляет дополнительные методы навигации. |
Реализация: TreeSet. |
- SortedMap |
Расширение Map, автоматически сортирует ключи. |
Реализация: TreeMap. |
- NavigableMap |
Расширение SortedMap, предоставляет дополнительные методы навигации. |
Реализация: TreeMap. |
| Потокобезопасные коллекции | Коллекции, безопасные для работы в многопоточной среде. | |
- Vector |
Синхронизированная версия ArrayList. |
Устаревшая, менее эффективна. |
- Stack |
Синхронизированная версия стека. | Устаревшая, рекомендуется использовать Deque. |
- ConcurrentHashMap |
Потокобезопасная реализация Map, более эффективная, чем синхронизация. |
Используется в многопоточных приложениях. |
| Критерий | ArrayList | LinkedList |
|---|---|---|
| Структура данных | Динамический массив | Двусвязный список |
| Доступ по индексу (get) | ✅ O(1) - очень быстрый | ❌ O(n) - медленный |
| Добавление в начало (addFirst) | ❌ O(n) - медленно | ✅ O(1) - очень быстро |
| Добавление в конец (addLast) | ✅ O(1) - быстро | ✅ O(1) - быстро |
| Удаление из начала (removeFirst) | ❌ O(n) - медленно | ✅ O(1) - очень быстро |
| Удаление из конца (removeLast) | ✅ O(1) - быстро | ✅ O(1) - быстро |
| Использование памяти | ✅ Экономичнее | ❌ Занимает больше |
| Производительность | ✅ Лучше в 95% случаев | ❌ Хуже в большинстве сценариев |
| Когда использовать | Для чтения и работы с данными | Для частых изменений в начале списка |
Java Collections Framework предоставляет набор интерфейсов и классов для работы с коллекциями данных
-
Collection: Базовый интерфейс для всех коллекций
-
List: Упорядоченная коллекция с возможностью дублирования элементов
List<String> list = new ArrayList<>
-
Set: Коллекция без дубликатов
Set<String> set = new HashSet<>
-
Queue: Коллекция для очередей (FIFO)
Queue<String> queue = new LinkedList<>
Представляет набор ключ-значение
-
HashMap: Хэш-таблица без гарантии порядка
Map<String, Integer> map = new HashMap<>
-
LinkedHashMap: Сохраняет порядок вставки
Map<String, Integer> linkedMap = new LinkedHashMap<>
-
TreeMap: Отсортированная по ключам коллекция
Map<String, Integer> treeMap = new TreeMap<>
- Единый интерфейс для различных типов коллекций
- Гибкость выбора реализации в зависимости от задачи
- Поддержка потокобезопасных коллекций через Collections.synchronizedXXX()
🔄 К содержанию - главы
🔼 К содержанию
| Коллекция | Метод | Описание |
|---|---|---|
| List | get(int index) | Получает элемент по индексу |
| List | set(int index, E element) | Заменяет элемент по индексу |
| List | indexOf(Object o) | Возвращает индекс первого вхождения |
| List | lastIndexOf(Object o) | Возвращает индекс последнего вхождения |
| List | subList(int from, int to) | Возвращает подсписок |
| ArrayList | ensureCapacity(int minCap) | Увеличивает ёмкость списка |
| LinkedList | addFirst(E e) | Добавляет элемент в начало |
| LinkedList | addLast(E e) | Добавляет элемент в конец |
| LinkedList | getFirst() | Получает первый элемент |
| LinkedList | getLast() | Получает последний элемент |
| Set | add(E e) | Добавляет элемент (если его нет) |
| Set | remove(Object o) | Удаляет элемент |
| Set | contains(Object o) | Проверяет наличие элемента |
| HashSet | clone() | Создаёт копию множества |
| TreeSet | first() | Первый (наименьший) элемент |
| TreeSet | last() | Последний (наибольший) элемент |
| TreeSet | higher(E e) | Элемент строго больше заданного |
| TreeSet | lower(E e) | Элемент строго меньше заданного |
| Map | put(K key, V value) | Добавляет пару ключ-значение |
| Map | get(Object key) | Получает значение по ключу |
| Map | remove(Object key) | Удаляет пару по ключу |
| Map | containsKey(Object key) | Проверяет наличие ключа |
| Map | containsValue(Object value) | Проверяет наличие значения |
| Map | keySet() | Возвращает множество ключей |
| Map | values() | Возвращает коллекцию значений |
| Map | entrySet() | Возвращает пары ключ-значение |
| HashMap | compute(K key, BiFunction) | Обновляет значение по ключу |
| TreeMap | firstEntry() | Первая пара ключ-значение |
| TreeMap | lastEntry() | Последняя пара ключ-значение |
| Queue | offer(E e) | Добавляет элемент (не выбрасывает исключение) |
| Queue | poll() | Удаляет и возвращает голову очереди |
| Queue | peek() | Возвращает голову очереди без удаления |
| Deque | push(E e) | Добавляет элемент в начало |
| Deque | pop() | Удаляет и возвращает элемент из начала |
| Deque | descendingIterator() | Итератор в обратном порядке |
🔄 К содержанию - главы
🔼 К содержанию
Коллизия в программировании — это ситуация, когда два или более элемента данных сталкиваются, нарушая ожидаемое поведение системы. Чаще всего коллизии рассматриваются в контексте хэш-функций.
Пример: В хэш-таблицах коллизия возникает, если два ключа имеют одинаковый хэш-значение и попадают в одно и то же "ведро" (bucket).
Методы разрешения коллизий:
- Цепочки (Chaining): Каждый bucket содержит список элементов, и при коллизии новый элемент добавляется в этот список.
- Открытая адресация (Open Addressing): Найдется другое свободное место для хранения элемента.
- Сбалансированные хэш-функции: Минимизация вероятности коллизий через улучшенные алгоритмы хэширования.
🔄 К содержанию - главы
🔼 К содержанию
Рефлексия — это механизм, с помощью которого программа может анализировать и изменять свое поведение во время выполнения.
Возможности рефлексии:
- Извлечение информации о классах, методах, конструкторах, полях и аннотациях.
- Динамическое создание объектов и вызов методов.
- Работа с приватными полями и методами (с нарушением инкапсуляции).
Недостатки рефлексии:
- Снижение производительности.
- Нарушение принципов инкапсуляции.
- Усложнение отладки.
Пример использования: Рефлексия активно применяется в фреймворках (например, Spring) для создания динамического поведения.
Рефлексия в Java реализуется через пакет java.lang.reflect и класс Class, который является центральным элементом механизма рефлексии.
| Компонент | Назначение |
|---|---|
Class |
Представляет метаинформацию о классе. Позволяет получить доступ к методам, полям, конструкторам и аннотациям. |
Method |
Представляет метод класса. Позволяет вызывать его динамически. |
Field |
Представляет поле класса. Позволяет читать и изменять его значение. |
Constructor |
Представляет конструктор класса. Позволяет создавать экземпляры. |
Modifier |
Предоставляет информацию о модификаторах доступа (public, private и т.д.). |
Annotation |
Позволяет работать с аннотациями в рантайме. |
Array, Proxy и др. |
Дополнительные классы для работы с массивами и динамическими прокси. |
Как это работает
- При загрузке класса JVM создает объект
Class, который содержит всю метаинформацию. - Через
Class.forName("имя_класса")можно получить доступ к этому объекту. - Далее можно извлекать методы, поля, конструкторы и вызывать их с помощью соответствующих API.
🔄 К содержанию - главы
🔼 К содержанию
Хэш-таблица — это структура данных, которая обеспечивает быстрый доступ к элементам на основе ключей. Элементы хранятся в массиве, доступ к которым осуществляется с использованием хэш-функции.
-
Ключ (Key): Уникальная идентифицирующая информация, которая используется для нахождения значения. Например, ключом может быть строка или число.
-
Хэш-функция: Алгоритм, который преобразует ключ в целочисленное значение (индекс). Это значение указывает, где хранить данные в массиве.
-
Бакет (Bucket): Место в массиве, куда помещаются значения. Если несколько ключей имеют одинаковый хэш-код, то они хранятся в одном бакете, используя метод разрешения коллизий.
-
Коллизия: Ситуация, когда два ключа генерируют одинаковый хэш-код. Это приводит к размещению нескольких элементов в одном бакете.
-
Метод цепочек (Chaining): Каждый бакет содержит список (или другую структуру данных), чтобы хранить элементы при коллизии.
-
Открытая адресация (Open Addressing):
Новый элемент помещается в другую свободную ячейку массива, если произошла коллизия. -
Перехэширование (Rehashing): Использование альтернативной хэш-функции для повторного распределения элементов.
- Быстрый доступ к данным по ключу: поиск, добавление и удаление происходят за O(1) в среднем случае.
- Эффективность работы при большом количестве элементов.
- Хэш-таблицы требуют хорошей хэш-функции для минимизации коллизий.
- Потребление памяти из-за необходимости хранения массива, включая пустые бакеты.
🔄 К содержанию - главы
🔼 К содержанию
Очередь — структура данных, работающая по принципу FIFO (First-In-First-Out).
Стек — структура данных, работающая по принципу LIFO (Last-In-First-Out).
Различия:
- Очередь позволяет добавлять элементы в конец и удалять с начала.
- Стек позволяет добавлять и удалять элементы только с одного конца.
Примеры использования:
- Очередь: управление задачами в многопоточных приложениях.
- Стек: выполнение операций обратной польской записи.
🔄 К содержанию - главы
🔼 К содержанию
- Что такое hashCode?
Метод hashCode — это метод, который возвращает целочисленное значение (хеш-код), представляющее объект. Это значение используется для определения положения объекта в структурах данных, основанных на хеш-таблицах, таких как HashMap, HashSet или Hashtable.
Зачем нужен hashCode?
Хеш-код помогает ускорить операции поиска, добавления и удаления элементов в коллекциях. Например, в HashMap объекты размещаются в "бакеты" (ячейки) на основе их хеш-кода. Таким образом, чтобы найти объект, программа сначала вычисляет его хеш-код и сразу переходит к соответствующему бакету, а не проверяет каждый элемент по очереди.
Основные правила работы с hashCode:
Связь с методом equals:
Если два объекта считаются равными согласно методу equals, их хеш-коды должны быть одинаковыми.
Однако если хеш-коды одинаковые, это не означает, что объекты равны (возможны коллизии).
Коллизия в контексте Java — это ситуация, когда два или более различных объекта имеют одинаковый хэш-код и попадают в одно и то же "ведро" (bucket) в хэш-таблице. Это происходит при использовании таких структур данных, как HashMap или HashSet.
Решение коллизий (теория):
- Метод цепочек (Chaining): Каждый bucket хранит список элементов. Если происходит коллизия, новый элемент добавляется в список.
- Открытая адресация (Open Addressing): При коллизии ищется другое свободное место в массиве для хранения элемента.
- Реализация собственных хэш-функций: Хэш-функции должны быть хорошо сбалансированными, чтобы минимизировать вероятность коллизий.
Переопределение:
По умолчанию метод hashCode наследуется от класса Object и вычисляет хеш-код на основе адреса объекта в памяти.
Если вы переопределяете метод equals (например, для сравнения объектов по содержимому полей), вам также нужно переопределить hashCode, чтобы обеспечить корректную работу коллекций.
Консистентность:
Хеш-код должен оставаться постоянным для одного и того же объекта, пока его состояние (поля), влияющие на вычисление хеш-кода, не меняется.
- Что такое equals? Метод equals используется для проверки равенства двух объектов на основе их содержимого, а не их ссылок в памяти. По умолчанию метод equals, унаследованный от класса Object, сравнивает объекты по их ссылкам (то есть проверяет, указывают ли две переменные на один и тот же объект в памяти). Однако часто требуется сравнивать объекты по их состоянию (например, значениям полей).
Зачем нужен equals? Когда вы создаете собственный класс, вам может потребоваться определить, какие объекты считаются равными с точки зрения логики программы. Например:
Два объекта Person могут считаться равными, если у них одинаковые имя и возраст.
Два объекта Book могут быть равны, если у них одинаковый ISBN.
Переопределение метода equals позволяет реализовать такую логику сравнения.
Основные правила работы с equals:
Связь с hashCode:
Если два объекта равны согласно методу equals, их хеш-коды должны быть одинаковыми.
Это правило необходимо для корректной работы коллекций, таких как HashMap или HashSet.
Симметричность:
Если a.equals(b) возвращает true, то b.equals(a) также должен возвращать true.
Транзитивность:
Если a.equals(b) и b.equals(c) возвращают true, то a.equals(c) тоже должен возвращать true.
Последовательность:
Результат equals должен оставаться постоянным, пока состояние объектов не меняется.
Сравнение с null:
Метод equals никогда не должен выбрасывать исключение при сравнении с null. Вместо этого он должен возвращать false.
3.Что такое хеш-таблицы и бакеты? Хеш-таблица — это эффективная структура данных, которая позволяет быстро выполнять операции добавления, удаления и поиска элементов. Она основана на использовании хеш-функции , которая преобразует ключ объекта в целочисленное значение (хеш-код), которое определяет, в какую ячейку (бакет) таблицы будет помещен этот объект.
Как работает хеш-таблица?
Хеш-функция:
Когда вы добавляете элемент в хеш-таблицу, его ключ обрабатывается хеш-функцией, которая вычисляет целочисленное значение (хеш-код). Это значение используется для определения конкретного бакета, куда будет помещен элемент.
Бакеты:
Бакеты — это внутренние ячейки хеш-таблицы. Каждый бакет может содержать один или несколько элементов. Хеш-код указывает, в какой бакет поместить элемент.
Поиск элемента:
При поиске элемента по ключу хеш-функция снова вычисляет хеш-код, чтобы найти нужный бакет. После этого выполняется сравнение с помощью метода equals, чтобы убедиться, что найденный элемент действительно соответствует ключу.
🔄 К содержанию - главы
🔼 К содержанию
Generics (обобщения) позволяют создавать классы, интерфейсы и методы, работающие с различными типами данных, при этом сохраняя типобезопасность.
Дженерики: Дженерики позволяют параметризировать классы, интерфейсы и методы типами. Это улучшает безопасность типов на этапе компиляции и делает код более устойчивым к ошибкам.
Ковариантность: Ковариантность позволяет использовать более специфичные типы по сравнению с указанным. Она полезна для чтения данных, но может ограничить возможность записи.
Контрвариантность: Контрвариантность допускает использование более общих типов. Она часто применяется там, где важна запись данных в коллекцию, но чтение ограничено объектами базового типа.
Инвариантность: Инвариантность подразумевает, что обобщённый тип нельзя заменить другим, даже если они связаны отношениями наследования. Для работы с наследованием используются ковариантные или контрвариантные wildcards.
| Понятие | Определение |
|---|---|
| Generics | Механизм, позволяющий создавать классы, интерфейсы и методы, которые работают с параметризованными типами. Это позволяет избежать явного приведения типов и обеспечивает более безопасную работу с данными во время компиляции. |
| Типовые параметры | Параметры типа (например, <T>, <E>, <K, V>), используемые для указания типа данных, который будет использоваться в классе, методе или интерфейсе. Они могут представлять любой тип, например, String, Integer или пользовательский класс. |
| Преимущества | - Безопасность типов: Компилятор проверяет соответствие типов на этапе компиляции, предотвращая ошибки времени выполнения. - Устранение приведения типов: Уменьшается необходимость использования оператора (Type) для преобразования объектов.- Код переиспользование: Одна реализация может работать с разными типами данных. |
| Ограничения типов | Возможность ограничить типы, которые могут быть использованы с generics, с помощью ключевого слова extends. Например, <T extends Number> означает, что параметр типа должен быть подклассом Number. |
| Wildcards | Используются для работы с неизвестными типами данных. Существует три основных вида: - ? — любой тип.- <? extends T> — любой тип, являющийся подтипом T.- <? super T> — любой тип, являющийся надтипом T. |
| Необходимость | Generics особенно полезны при работе с коллекциями, так как они позволяют хранить элементы одного типа, исключая возможность добавления неправильных типов данных. Например, List<String> может содержать только строки. |
| Стерилизация | Когда код, использующий generics, компилируется, компилятор выполняет процесс стирания типов (type erasure). Это означает, что в байт-коде все типовые параметры заменяются их ограничениями (или Object, если ограничений нет). |
| Недостатки | - Невозможность создания экземпляров параметризованного типа (new T() недопустимо).- Нельзя использовать примитивные типы (например, int, char) в качестве параметров типа; вместо них нужно использовать обертки (Integer, Character). |
| Вид Generics | Описание | Пример использования |
|---|---|---|
| Простые Generics | Базовый тип параметризации, где используется один параметр типа для обобщения. | List<T> — коллекция объектов типа T. |
| Множественные Generics | Позволяет использовать несколько параметров типов одновременно. | Map<K, V> — словарь с ключами типа K и значениями типа V. |
| Ограниченные Generics | Указывает ограничения на типы, которые могут быть использованы с generics. | <T extends Number> — T должен быть подклассом Number. |
| Нижние границы Generics | Указывает, что тип должен быть надтипом указанного класса. | <T super Integer> — T должен быть надтипом Integer. |
| Wildcards (Звездочки) | Используются для работы с неизвестными или универсальными типами данных. | |
| - Unbounded Wildcard | Обозначает любой тип (?). |
List<?> — список любого типа. |
| - Upper Bounded Wildcard | Обозначает тип, который является подклассом указанного класса (<? extends T>). |
List<? extends Number> — список подклассов Number. |
| - Lower Bounded Wildcard | Обозначает тип, который является надклассом указанного класса (<? super T>). |
List<? super Integer> — список надклассов Integer. |
| Статические Generics | Позволяет создавать статические методы, поддерживающие параметры типов. | public static <T> void printArray(T[] array) |
| Generic Methods | Методы, которые принимают или возвращают параметризованные типы, независимо от класса. | public <T> T getFirstElement(List<T> list) |
| Generic Classes | Классы, которые определены с параметрами типов, позволяя работать с различными типами данных. | public class Box<T> { private T content; } |
| Generic Interfaces | Интерфейсы, которые используют параметры типов для абстракции различных типов данных. | public interface Comparator<T> { int compare(T o1, T o2); } |
| Type Erasure | Процесс, при котором компилятор заменяет все параметры типов на их ограничения или Object. |
Компилятор преобразует List<String> в List<Object>. |
-
Основная идея:
- Generics обеспечивают возможность использовать параметризованные типы, что позволяет избежать приведения типов и уменьшить количество ошибок во время выполнения.
- Пример:
List<String> list = new ArrayList<>(); listadd("Hello"); String str = listget(0); // Без явного приведения типа
-
Ограничения типов:
- Можно указывать ограничения для параметров типа с помощью ключевого слова
extends. - Пример:
class Box<T extends Number> { private T value; public void set(T value) { thisvalue = value; } public T get() { return value; } }
- Можно указывать ограничения для параметров типа с помощью ключевого слова
-
Wildcards:
- Используются для работы с неизвестными типами.
- Пример:
List<?> list = new ArrayList<>(); // Любой тип List<? extends Number> numbers = new ArrayList<>(); // Подтип Number List<? super Integer> integers = new ArrayList<>(); // Супертип Integer
-
Type Erasure:
- Во время компиляции информация о типах generics удаляется (type erasure), поэтому generics работают только на уровне компиляции.
- Это может привести к ограничениям, например, нельзя создать новый экземпляр параметризованного типа.
🔄 К содержанию - главы
🔼 К содержанию
В Java управление памятью автоматизировано, что делает язык более безопасным и удобным для использования. Память делится на несколько областей:
Stack (Стек) : Хранит локальные переменные и информацию о вызовах методов. Каждый поток имеет свой собственный стек.
Heap (Куча) : Общая область памяти, где создаются все объекты. Управление памятью здесь осуществляется через механизм сборки мусора.
Method Area (Область методов) : Хранит метаданные классов, такие как имена, типы и код методов.
PC Register (Регистр команд) : Отслеживает текущую выполняемую инструкцию для каждого потока.
Native Method Stack (Стек нативных методов) : Используется для выполнения методов, написанных на других языках программирования.
Сборщик мусора (Garbage Collector) автоматически удаляет объекты, которые больше недоступны для программы. Это позволяет разработчику не беспокоиться о ручном освобождении памяти, снижая риск утечек.
Метод finalize() — это специальный метод в Java, который был предназначен для выполнения очистки ресурсов перед тем, как объект будет удален сборщиком мусора. Однако его использование считается устаревшим и не рекомендуется в современных приложениях.
Что такое finalize()?
Метод finalize() определен в классе Object и может быть переопределен в подклассах.
Он вызывается JIT-компилятором (Just-In-Time Compiler) перед удалением объекта сборщиком мусора.
Его основное назначение — выполнить действия по очистке ресурсов (например, закрыть файлы, сокеты или другие внешние ресурсы).
Альтернативы finalize() Современные подходы к управлению ресурсами в Java:
Интерфейс AutoCloseable и конструкция try-with-resources:
Используется для автоматического закрытия ресурсов (например, файлов, соединений с базой данных).
После выхода из блока try, ресурс автоматически закрывается.
Ручное управление ресурсами:
Явно вызывать методы для освобождения ресурсов (например, close() для файлов или disconnect() для сетевых соединений).
Финализаторы заменены на Cleaner и PhantomReference:
В Java 9 появился класс java.lang.ref.Cleaner, который является более эффективной альтернативой finalize().
PhantomReference позволяет отслеживать объекты, готовые к сборке мусора, без использования finalize().
- Используется для хранения локальных переменных и информации о вызовах методов.
- Каждый поток имеет свой собственный стек.
- Локальные переменные, примитивные типы данных и ссылки на объекты хранятся здесь.
- Размер стека ограничен, что может привести к
StackOverflowError, если глубина вызовов методов слишком велика.
- Общая область памяти для всех потоков, где создаются объекты.
- Управление памятью в куче осуществляется автоматически через механизм сборки мусора (Garbage Collector).
- Все объекты, созданные с помощью оператора
new, выделяются в куче. - Размер кучи можно настраивать через параметры JVM.
- Часть памяти, используемая для хранения структуры классов, таких как метаданные классов, код методов и константы.
- Включает в себя String Pool — пул строк, где хранятся литеральные строки.
- Является общей для всех потоков.
- Содержит адрес текущей выполняемой инструкции для каждого потока.
- Отслеживает порядок выполнения команд.
- Используется для выполнения нативных методов (методов, написанных на языках, отличных от Java, таких как C или C++).
- Аналогичен обычному стеку, но нативный код.
- Автоматический механизм очистки памяти в куче.
- Освобождает память, занимаемую объектами, которые больше не доступны для программы.
- Работает асинхронно и может временно приостанавливать выполнение программы (pause).
| Раздел памяти | Входит в... | Общий или Потокозависимый? | Что хранит? | Главное отличие / Особенность |
|---|---|---|---|---|
| Heap (Куча) | JVM | Общий (для всех потоков) | Все объекты (экземпляры классов), созданные через new. |
Управляется Сборщиком Мусора (GC). Основная область для данных приложения. |
| Method Area (Область Методов) | JVM | Общий (для всех потоков) | Метаданные классов, код методов, статические переменные, String Pool. | Хранит "чертежи" и постоянную информацию о структуре программы. |
| Stack (Стек) | JVM | Потокозависимый (у каждого потока свой) | Локальные переменные, примитивные типы, ссылки на объекты в Куче, информация о вызовах методов (фреймы). | Работает по принципу LIFO (последний пришёл — первый ушёл). Вызывает StackOverflowError. |
| PC Register (Регистр Команд) | JVM | Потокозависимый (у каждого потока свой) | Адрес текущей выполняемой инструкции JVM для данного потока. | Помогает потоку "помнить", где он остановился, чтобы продолжить работу после переключения. |
| Native Method Stack (Стек Нативных Методов) | JVM | Потокозависимый (у каждого потока свой) | Используется для нативных методов (код на C/C++), вызванных из Java-кода. | Аналогичен обычному Стеку, но для кода, не написанного на Java. |
Сборщик мусора (Garbage Collector) не является областью памяти, но это ключевой механизм, работающий с Кучей (Heap).
- Задача: Освобождать место в Куче, удаляя те объекты, на которые больше нет ни одной ссылки из работающей программы (они недостижимы).
- Особенность: Это автоматическое управление памятью. Программисту не нужно вручную удалять объекты, как в C++.
- Минус: Иногда GC должен остановить все потоки приложения (так называемая "пауза" или Stop-The-World), чтобы выполнить очистку, что может вызвать небольшие задержки.
🔄 К содержанию - главы
🔼 К содержанию
Строки в Java являются неизменяемыми (immutable), что означает, что их содержимое нельзя изменить после создания.
Пул строк — это специальная область памяти в Java Heap(Куча), где хранятся литеральные строки (строки, объявленные как "текст"). JVM автоматически управляет этим пулом для оптимизации использования памяти. Если строка уже существует в пуле, вместо создания новой копии ссылается на существующий объект.
Строка (String) в Java представляет собой неизменяемую (иммутабельную) последовательность символов. Класс String является частью пакета java.lang и используется для работы с текстовыми данными. Поскольку строки являются иммутабельными, любая операция, изменяющая строку (например, конкатенация или замена символов), на самом деле создает новую строку.
-
Пул строк:
- Java автоматически сохраняет строки в пуле для оптимизации использования памяти.
- Если строка уже существует в пуле, создается ссылка на существующую строку, а не новая копия.
- Пример:
String str1 = "Hello"; String str2 = "Hello"; Systemoutprintln(str1 == str2); // true, так как строки берутся из пула
-
new String:
- Создание строки с использованием оператора
newвсегда приводит к созданию нового объекта в памяти, даже если такая строка уже существует в пуле. - Пример:
String str3 = new String("Hello"); Systemoutprintln(str1 == str3); // false, так как str3 создан вне пула
- Создание строки с использованием оператора
-
intern:
- Метод
intern()добавляет строку в пул, если её там нет. - Пример:
String str4 = new String("Hello").intern(); Systemoutprintln(str1 == str4); // true, так как str4 теперь ссылается на строку из пула
- Метод
🔄 К содержанию - главы
🔼 К содержанию
- При передаче параметров по значению (call-by-value) в метод копируется значение аргумента.
- Любые изменения, произведенные внутри метода с этими параметрами, не влияют на оригинальные данные за пределами метода.
- В Java используется только call-by-value, даже при работе с объектами.
- Когда передается объект, kopия ссылки на этот объект передается в метод.
- Это позволяет изменять состояние объекта (например, его поля) внутри метода, но не позволяет заменить сам объект на другой.
| Особенность | Call-by-value | Call-by-reference |
|---|---|---|
| Передача данных | Передается копия значения или ссылки. | Передается сама ссылка на данные. |
| Изменение параметров | Изменения внутри метода не влияют на оригинальные данные. | Изменения внутри метода влияют на оригинальные данные. |
| Java | Используется только call-by-value, даже для объектов (передается копия ссылки). | Языки, такие как C++ или Python, поддерживают call-by-reference для некоторых типов. |
- В Java всегда используется call-by-value.
- Для примитивных типов передается копия значения.
- Для объектов передается копия ссылки, что позволяет изменять состояние объекта, но не заменять сам объект.
🔄 К содержанию - главы
🔼 К содержанию
| Метод | Возвращаемый тип | Описание |
|---|---|---|
toString() |
String |
Возвращает строковое представление объекта. Может быть переопределен для более осмысленного вывода. |
equals(Object obj) |
boolean |
Сравнивает этот объект с указанным объектом (obj). По умолчанию сравнивает ссылки. |
hashCode() |
int |
Возвращает хэш-код объекта. Должен быть согласован с методом equals(). |
clone() |
Object |
Создает и возвращает копию объекта. Класс должен реализовать интерфейс Cloneable. |
finalize() |
void |
Вызывается перед сборкой мусора. Устаревший с Java 9, не рекомендуется использовать. |
getClass() |
Class<?> |
Возвращает объект типа Class, представляющий класс этого объекта. |
notify() |
void |
Будит один поток, который ждет на этом объекте. Используется в многопоточности. |
notifyAll() |
void |
Будит все потоки, которые ждут на этом объекте. |
wait() |
void |
Приостанавливает выполнение текущего потока, пока другой поток не вызовет notify() или notifyAll(). |
wait(long timeout) |
void |
Аналогично wait(), но с таймаутом в миллисекундах. |
wait(long timeout, int nanos) |
void |
Аналогично wait(long timeout), но с точностью до наносекунд. |
Класс Object является суперклассом всех классов в Java. Он предоставляет базовые методы, которые могут быть переопределены в подклассах.
-
toString:
- Возвращает строковое представление объекта.
- Переопределяется для удобного вывода информации о состоянии объекта.
- Пример:
@Override public String toString() { return "MyClass{" + "field1=" + field1 + ", field2=" + field2 + '}'; }
-
equals:
- Описан выше. Используется для сравнения объектов.
-
hashCode:
- Описан выше. Используется для работы с хеш-таблицами.
-
clone:
- Создает копию объекта. Требует реализации интерфейса
Cloneable. - Пример:
@Override protected MyClass clone() throws CloneNotSupportedException { return (MyClass) super.clone(); }
- Создает копию объекта. Требует реализации интерфейса
-
finalize (устаревший):
- Вызывается перед сборкой мусора для выполнения очистки ресурсов.
- Не рекомендуется использовать из-за неопределённости времени вызова.
-
getClass:
- Возвращает объект
Class, представляющий тип объекта.
- Возвращает объект
-
wait/notify/notifyAll:
- Используются для синхронизации потоков.
- Пример:
synchronized (this) { wait(); // Приостанавливает текущий поток notify(); // Пробуждает один поток }
🔄 К содержанию - главы
🔼 К содержанию
JVM, Java Virtual Machine (Виртуальная машина Java) — основная часть среды времени исполнения Java (JRE). Виртуальная машина Java исполняет байт-код Java, предварительно созданный из исходного текста Java-программы компилятором Java.
JRE, Java Runtime Environment (Среда времени выполнения Java) - минимально-необходимая реализация виртуальной машины для исполнения Java-приложений.
JDK, Java Development Kit (Комплект разработки на Java) - среда для разработки программ на Java, включающая в себя JRE - среду для обеспечения запуска Java программ, которая в свою очередь содержит JVM - интерпретатор кода Java программ.
Java — строго типизированный язык программирования, требующий явного объявления типов переменных. Программа всегда начинается с класса, который содержит метод main. Этот метод является точкой входа программы.
Основные правила синтаксиса включают:
Все операции выполняются внутри блоков, ограниченных фигурными скобками {}. Инструкции завершаются точкой с запятой (;). Комментарии пишутся с помощью // (однострочный) или /* ... */ (многострочный).
Структура программы включает объявление переменных, методов и классов. Каждый класс может содержать поля (переменные), методы (функции) и конструкторы для создания объектов.
Метод main является основной точкой входа в программу на Java. Без этого метода программа не сможет быть выполнена, так как JVM (Java Virtual Machine) ищет именно его для запуска.
🔄 К содержанию - главы
🔼 К содержанию
Интерфейсы в Java — это как "правила игры", которые класс должен соблюдать. Они помогают определить, какие действия объект должен уметь выполнять, но не указывают, как именно их выполнять.
Интерфейс — это набор методов без реализации (то есть без тела), который классы обязаны реализовать.
Когда класс реализует интерфейс, он гарантирует выполнение всех методов, описанных в интерфейсе.
- Методы без тела (реализации).
- Классы, реализующие интерфейс, обязаны предоставить реализацию всех абстрактных методов.
- Переменные с модификаторами
public static final. - Доступны всем классам, реализующим интерфейс.
- Неизменяемы (константы).
- Добавлены с Java 8.
- Содержат реализацию по умолчанию.
- Позволяют добавлять новые методы в интерфейс, не нарушая работу существующих классов.
- Также появились с Java 8.
- Вызываются напрямую через имя интерфейса.
- Не могут быть переопределены в классах, реализующих интерфейс.
- В Java класс может наследоваться только от одного класса, но реализовывать несколько интерфейсов.
- Обеспечивает гибкость при проектировании.
- Определяют единые правила для множества классов.
- Позволяют работать с объектами различных классов одинаково через ссылки на интерфейс.
| Тип интерфейса | Описание | Примеры интерфейсов |
|---|---|---|
| Маркерный | Не содержит методов. Используется для обозначения свойств объектов. | Serializable, Cloneable |
| Функциональный | Содержит один абстрактный метод. Часто применяется в лямбда-выражениях. | Runnable, Callable, Function<T, R> |
| Нормальный | Содержит один или более абстрактных методов и может включать default, static, private методы. |
List, Map, Set |
| Интерфейс с вложенными интерфейсами | Может содержать вложенные интерфейсы для логической группировки или структурирования API. | Map.Entry<K, V> |
| Потребительский (Consumer) | Интерфейсы, которые потребляют данные, не возвращая результата. Используются в обработке данных. | Consumer<T>, BiConsumer<T, U> |
🔄 К содержанию - главы
🔼 К содержанию
Методы в Java — это блоки кода, выполняющие определенные действия. Они обеспечивают переиспользование кода, инкапсуляцию и структурирование программы.
Метод — это именованный блок кода, который выполняет определенную задачу и может возвращать результат. Методы могут принимать параметры и могут быть вызваны несколько раз из различных мест программы.
- Состоит из модификаторов доступа, типа возвращаемого значения, имени метода и параметров (если есть).
- Пример объявления (без реализации):
public int add(int a, int b)
- Передаваемые значения, необходимые для выполнения метода.
- Могут быть примитивными типами или объектами.
- Тип, который метод возвращает (
int,String,voidи т. д.). voidозначает, что метод ничего не возвращает.
| Тип метода | Описание |
|---|---|
| Статический метод | Объявляется с ключевым словом static. Вызывается через имя класса. |
| Экземплярный метод | Принадлежит объекту класса. Требует создания экземпляра для вызова. |
| Абстрактный метод | Объявляется с ключевым словом abstract. Не имеет реализации. Реализуется в подклассах. |
| Метод по умолчанию | Объявляется в интерфейсах с ключевым словом default. Имеет реализацию. |
| Финализированный метод | Объявляется с ключевым словом final. Не может быть переопределен в подклассах. |
| Синхронизированный метод | Объявляется с ключевым словом synchronized. Обеспечивает потокобезопасность. |
| Конструктор | Специальный метод, вызываемый при создании объекта. Не имеет типа возвращаемого значения. |
| Перегруженный метод | Метод с тем же именем, но с разными параметрами. |
| Нативный метод | Объявляется с ключевым словом native. Реализуется вне Java (например, на C/C++). |
| Private метод | Объявляется с ключевым словом private. Доступен только внутри класса. |
| Protected метод | Объявляется с ключевым словом protected. Доступен внутри пакета и в подклассах. |
| Public метод | Объявляется с ключевым словом public. Доступен из любого места программы. |
| Пакетно-приватный метод | Метод без модификатора доступа. Доступен только внутри пакета. |
| Метод с переменным числом аргументов | Объявляется с использованием ... после типа параметра. Позволяет передавать произвольное количество аргументов. |
| Переопределенный метод | Метод, который переопределяет метод родительского класса с помощью аннотации @Override. |
| Лямбда-выражение | Не является методом в классическом смысле, но используется как анонимная реализация функционального интерфейса. |
| Метод, объявленный в enum | Метод, определенный внутри перечисления (enum). Может быть статическим или экземплярным. |
| Метод, объявленный в record | Метод, определенный внутри записи (record). Может быть как автоматически сгенерированным, так и пользовательским. |
Метод, помеченный как strictfp |
Объявляется с ключевым словом strictfp. Гарантирует одинаковое поведение операций с плавающей точкой на всех платформах. |
| Метод с возвращаемым значением | Метод, который возвращает значение определенного типа (например, int, String). |
| Метод без возвращаемого значения | Метод, объявленный с типом возвращаемого значения void. Не возвращает никаких данных. |
| Модификатор | Описание |
|---|---|
public |
Доступен из любого класса. |
protected |
Доступен из классов того же пакета и подклассов. |
private |
Доступен только внутри объявляющего класса. |
| (Без модификатора) | Доступен только внутри пакета (package-private). |
- Создание нескольких методов с одним именем, но разными параметрами.
- Позволяет разные способы вызова метода в зависимости от параметров.
- Позволяет подклассу предоставить свою реализацию метода, объявленного в суперклассе.
- Требуется одинаковая сигнатура метода (имя, параметры и тип возвращаемого значения).
| Тип метода | На английском | Модификатор доступа | Можно переопределять? | Описание |
|---|---|---|---|---|
| Абстрактный | Abstract | public | Да (обязательно) | Метод без реализации. Классы, реализующие интерфейс, должны его реализовать. |
| По умолчанию | Default | public | Да (опционально) | Метод с реализацией, добавленный с Java 8. Можно переопределить в классе. |
| Статический | Static | public | Нет | Метод, который можно вызывать через имя интерфейса. Не наследуется. |
| Приватный | Private | private | Нет | Метод, используемый внутри интерфейса для разбиения логики. |
🔄 К содержанию - главы
🔼 К содержанию
Класс — это шаблон или структура в объектно-ориентированном программировании (ООП), которая описывает свойства (поля) и поведение (методы) объектов. Он используется для создания экземпляров (объектов), которые имеют одинаковые характеристики и поведение.
- Поля: Переменные, которые хранят данные или состояние объекта.
- Методы: Действия или функции, которые определяют поведение объекта.
- Конструкторы: Специальные методы для инициализации объектов при их создании.
- Модификаторы доступа: Указывают доступность элементов класса (например,
public,private,protected). - Статические элементы: Методы или поля, принадлежащие всему классу, а не конкретным объектам.
| Тип класса | Описание | Примеры |
|---|---|---|
| Обычные классы | Основные классы, которые используются для описания сущностей. | Person, Animal |
| Абстрактные классы | Классы, которые не могут быть инстанцированы и служат базой для других классов. | Shape, Vehicle |
| Вложенные (Nested) классы | Классы, определенные внутри других классов. Делятся на статические и нестатические. | Outer.Inner |
| Анонимные классы | Классы без имени, которые обычно используются для переопределения методов интерфейсов. | Реализация Runnable |
| Финальные классы | Классы, которые нельзя наследовать (объявляются с ключевым словом final). |
String |
| Классы-оболочки (Wrapper) | Классы, которые оборачивают примитивные типы данных, чтобы работать с ними как с объектами. | Integer, Double |
| Иммутабельные классы | Классы, состояние объектов которых не может быть изменено после создания. | String, BigDecimal |
- Инкапсуляция данных и поведения.
- Повышение повторного использования кода за счет наследования.
- Легкость создания и работы с объектами.
- Улучшение структурирования программы.
🔄 К содержанию - главы
🔼 К содержанию
Множественное наследование в Java: Почему интерфейсы, а не классы?
Что такое множественное наследование?
Множественное наследование — это когда один класс может брать свойства и методы сразу от нескольких родительских классов. Это как если бы вы могли научиться одновременно готовить, петь и танцевать, используя умения из разных людей.
Почему Java не поддерживает множественное наследование через классы? Казалось бы, множественное наследование — это удобно, но оно может привести к серьезным проблемам:
Конфликты методов : Если два родителя имеют методы с одинаковым названием, какой из них выбрать? Компьютер запутается. Проблема алмазной формы: Представьте такую цепочку: Класс A — общий предок. От него наследуются классы B и C. Класс D наследуется от обоих B и C. Если B и C переопределяют один и тот же метод из A, то как понять, чья версия нужна в D? Это вызывает путаницу. Из-за этих сложностей Java решила отказаться от множественного наследования через классы.
Как интерфейсы помогают решить эту проблему? Вместо классов Java предлагает использовать интерфейсы для множественного наследования. Интерфейсы — это как список правил, которые класс должен выполнить, но сам интерфейс не содержит конкретного кода.
Интерфейсы содержат только "шаблоны" методов : В них нет готового кода, только описание того, какие методы должны быть. Класс, который реализует этот интерфейс, сам решает, как именно будет летать. Нет состояния (полей) : Интерфейсы не хранят данные, поэтому не возникает конфликтов из-за полей. Методы по умолчанию (начиная с Java 8) : Теперь интерфейсы могут иметь методы с готовым кодом, помеченные как default. Но если несколько интерфейсов предоставляют одинаковые методы, класс должен явно выбрать, какой использовать. Это исключает неоднозначность.
🔄 К содержанию - главы
🔼 К содержанию
Паттерны проектирования можно классифицировать на три основные группы: порождающие, структурные и поведенческие. Ниже представлены эти группы в виде таблиц.
| Паттерн | Описание |
|---|---|
| Singleton | Обеспечивает наличие единственного экземпляра класса и предоставляет к нему глобальный доступ. |
| Factory Method | Определяет интерфейс для создания объектов, позволяя подклассам решать, какие объекты создавать. |
| Abstract Factory | Предоставляет интерфейс для создания семейств связанных или зависимых объектов. |
| Builder | Разделяет процесс конструирования сложного объекта от его представления. |
| Prototype | Создает новые объекты путем копирования существующих (прототипов). |
| Паттерн | Описание |
|---|---|
| Adapter | Преобразует интерфейс одного класса в другой, ожидаемый клиентом. |
| Bridge | Разделяет абстракцию и реализацию, позволяя им изменяться независимо. |
| Composite | Позволяет создавать древовидные структуры объектов с единым интерфейсом. |
| Decorator | Динамически добавляет дополнительное поведение объектам без изменения их класса. |
| Facade | Предоставляет упрощенный интерфейс к сложной системе классов. |
| Flyweight | Минимизирует использование памяти за счет разделяемых данных. |
| Proxy | Предоставляет объект-заместитель для контроля доступа к другому объекту. |
| Паттерн | Описание |
|---|---|
| Chain of Responsibility | Создает цепочку обработчиков для передачи запросов до тех пор, пока он не будет обработан. |
| Command | Преобразует запросы в объекты для параметризации клиентов различными запросами. |
| Interpreter | Определяет грамматику для языка и интерпретирует предложения этого языка. |
| Iterator | Предоставляет способ последовательного доступа ко всем элементам коллекции. |
| Mediator | Инкапсулирует взаимодействие между множеством объектов. |
| Memento | Сохраняет состояние объекта для его восстановления в будущем. |
| Observer | Определяет зависимость между объектами для автоматического уведомления при изменении состояния. |
| State | Позволяет объекту изменять свое поведение в зависимости от внутреннего состояния. |
| Strategy | Определяет семейство алгоритмов, инкапсулируя каждый из них и делая их взаимозаменяемыми. |
| Template Method | Определяет скелет алгоритма, позволяя подклассам переопределить некоторые шаги. |
| Visitor | Позволяет определить новую операцию над каждым элементом структуры данных. |
🔄 К содержанию - главы
🔼 К содержанию
Принципы SOLID:
- S - Single Responsibility Principle (Принцип единственной ответственности): Каждый класс должен иметь одну и только одну причину для изменения.
- O - Open/Closed Principle (Принцип открытости/закрытости): Код должен быть открыт для расширения, но закрыт для изменения.
- L - Liskov Substitution Principle (Принцип подстановки Барбары Лисков): Объекты базового класса могут быть заменены объектами его подкласса без изменения корректности программы.
- I - Interface Segregation Principle (Принцип разделения интерфейсов): Интерфейс не должен заставлять реализовывать методы, которые не используются.
- D - Dependency Inversion Principle (Принцип инверсии зависимостей): Модули верхнего уровня не должны зависеть от модулей нижнего уровня; оба должны зависеть от абстракций.
Don't Repeat Yourself (Не повторяй себя):
- Основной принцип: избегать дублирования кода.
- Повторяющийся код заменяется переиспользуемыми компонентами, функциями или классами.
- Это помогает уменьшить количество ошибок и упростить поддержку кода.
Keep It Simple, Stupid (Делай проще):
- Этот принцип гласит, что система должна быть настолько простой, насколько возможно.
- Избегай ненужной сложности в дизайне и реализации.
- Простота облегчает понимание, поддержку и улучшение системы.
You Aren't Gonna Need It (Тебе это не понадобится):
- Не добавляй функциональность, которая может быть нужна в будущем, но не требуется прямо сейчас.
- Сконцентрируйся на текущих потребностях, чтобы избежать лишнего кода и затрат.
General Responsibility Assignment Software Patterns (Шаблоны назначения ответственности):
- Предлагает подходы к распределению обязанностей между классами и объектами в программной системе.
- Включает такие шаблоны, как "Контроллер", "Информационный эксперт" и другие.
Convention over Configuration (Конвенция вместо конфигурации):
- В систему заложены стандартные настройки, которые используются по умолчанию.
- Это уменьшает количество ручной конфигурации и делает процесс разработки более эффективным.
Инкапсуляция:
- Скрытие внутренней реализации и данных класса от внешнего мира.
- Обеспечивает доступ к функциональности класса через строго определённые интерфейсы.
Полиморфизм:
- Возможность использования одного интерфейса для различных реализаций.
- Это позволяет создавать код, независимый от конкретных типов.
🔄 К содержанию - главы
🔼 К содержанию
