🤔 Что такое адаптер?
Адаптер (Adapter) – это шаблон проектирования, который используется для приведения интерфейсов несовместимых классов к единому виду. Он выступает посредником между двумя несовместимыми системами.
🚩Пример: Адаптер в Java (Object Adapter)
Допустим, у нас есть старый класс
Старый интерфейс (неподходящий)
Новый интерфейс (нужный)
Адаптер, который превращает
Использование адаптера
Object Adapter (адаптер-объект) – использует композицию (пример выше).
Class Adapter (адаптер-класс) – использует наследование (
Ставь 👍 и забирай 📚 Базу знаний
Адаптер (Adapter) – это шаблон проектирования, который используется для приведения интерфейсов несовместимых классов к единому виду. Он выступает посредником между двумя несовместимыми системами.
🚩Пример: Адаптер в Java (Object Adapter)
Допустим, у нас есть старый класс
OldCharger, который работает с вольтажем 220V, а мы хотим, чтобы он работал с USB (5V). Старый интерфейс (неподходящий)
class OldCharger {
void charge220V() {
System.out.println("Зарядка 220V...");
}
}Новый интерфейс (нужный)
interface USBCharger {
void charge5V();
}Адаптер, который превращает
220V в 5Vclass ChargerAdapter implements USBCharger {
private OldCharger oldCharger;
public ChargerAdapter(OldCharger oldCharger) {
this.oldCharger = oldCharger;
}
@Override
public void charge5V() {
System.out.println("Преобразуем 220V в 5V...");
oldCharger.charge220V();
}
}Использование адаптера
public class Main {
public static void main(String[] args) {
OldCharger oldCharger = new OldCharger();
USBCharger adapter = new ChargerAdapter(oldCharger);
adapter.charge5V(); // Теперь старая зарядка работает с 5V!
}
}Object Adapter (адаптер-объект) – использует композицию (пример выше).
Class Adapter (адаптер-класс) – использует наследование (
extends). class ChargerAdapter extends OldCharger implements USBCharger {
@Override
public void charge5V() {
System.out.println("Преобразуем 220V в 5V...");
charge220V();
}
}Ставь 👍 и забирай 📚 Базу знаний
👍10
🤔 Чем rebase отличается от merge?
1. Rebase переносит изменения текущей ветки на базу другой ветки, перезаписывая историю коммитов.
2. Merge объединяет изменения двух веток, создавая дополнительный коммит слияния.
3. Rebase делает историю линейной и чистой, но может быть сложен для командной работы .
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
2. Merge объединяет изменения двух веток, создавая дополнительный коммит слияния.
3. Rebase делает историю линейной и чистой, но может быть сложен для командной работы
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
👍8🔥7🤔3
🤔 Какие Fetching Types знаешь в Hibernate и чем они отличаются?
В Hibernate существует два типа загрузки (Fetching Types) данных:
Lazy (ленивая загрузка)
Eager (жадная загрузка)
Эти типы определяют, как Hibernate загружает связанные сущности при выполнении запроса.
🚩Lazy Fetching (ленивая загрузка)
Данные загружаются только при первом обращении к ним.
Экономит память и ресурсы, так как ненужные данные не загружаются сразу.
Используется по умолчанию в
🚩Eager Fetching (жадная загрузка)
Hibernate загружает все связанные данные сразу, даже если они не нужны.
Увеличивает время выполнения запроса, так как делает
Используется по умолчанию в
Ставь 👍 и забирай 📚 Базу знаний
В Hibernate существует два типа загрузки (Fetching Types) данных:
Lazy (ленивая загрузка)
Eager (жадная загрузка)
Эти типы определяют, как Hibernate загружает связанные сущности при выполнении запроса.
🚩Lazy Fetching (ленивая загрузка)
Данные загружаются только при первом обращении к ним.
Экономит память и ресурсы, так как ненужные данные не загружаются сразу.
Используется по умолчанию в
@OneToMany, @ManyToMany. @Entity
class User {
@Id @GeneratedValue
private Long id;
private String name;
@OneToMany(mappedBy = "user", fetch = FetchType.LAZY)
private List<Order> orders; // Загрузятся ТОЛЬКО при первом вызове getOrders()
}
User user = session.get(User.class, 1L); // Загружается только User
List<Order> orders = user.getOrders(); // Запрос в БД выполняется ТОЛЬКО здесь
🚩Eager Fetching (жадная загрузка)
Hibernate загружает все связанные данные сразу, даже если они не нужны.
Увеличивает время выполнения запроса, так как делает
JOIN или несколько отдельных запросов. Используется по умолчанию в
@ManyToOne, @OneToOne. @Entity
class User {
@Id @GeneratedValue
private Long id;
private String name;
@OneToMany(mappedBy = "user", fetch = FetchType.EAGER)
private List<Order> orders; // Загружается сразу при получении User
}
User user = session.get(User.class, 1L); // Загружается User + сразу все его Orders
Ставь 👍 и забирай 📚 Базу знаний
👍5
🤔 Как package-private можно связать с инкапсуляцией?
Package-private (доступ по умолчанию) усиливает инкапсуляцию, так как ограничивает видимость классов и методов только рамками одного пакета. Это позволяет:
- Скрывать реализацию, но при этом предоставлять доступ к необходимым компонентам внутри пакета.
- Разделять внутреннюю логику и публичный API.
- Предотвращать ненужное использование методов извне, сохраняя принцип "минимального раскрытия".
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
- Скрывать реализацию, но при этом предоставлять доступ к необходимым компонентам внутри пакета.
- Разделять внутреннюю логику и публичный API.
- Предотвращать ненужное использование методов извне, сохраняя принцип "минимального раскрытия".
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
👍9🔥3
🤔 Что такое Appender в log4j?
Это компонент, который отвечает за отправку логов в различные места назначения, такие как файлы, консоль, базы данных, сетевые сокеты или даже удаленные серверы. Каждый Appender реализует конкретный способ обработки и хранения логов.
🚩Зачем нужен Appender?
Appender позволяет гибко управлять тем, куда и как сохраняются логи. В зависимости от требований приложения, вы можете:
Писать логи в файл.
Выводить их в консоль.
Отправлять их в удалённые хранилища или базы данных.
🚩Основные виды Appender в Log4j
🟠ConsoleAppender
Логи выводятся в консоль.
Полезно для разработки и отладки.
🟠FileAppender
Логи записываются в файл.
Используется для длительного хранения логов.
🟠RollingFileAppender
Расширение FileAppender с возможностью ротации логов (ограничение размера файла, создание новых файлов при переполнении).
🟠DailyRollingFileAppender
Логи записываются в файл, который ротационно создаётся каждый день.
🟠SocketAppender
Отправляет логи через сеть (TCP или UDP).
Используется для централизованного логирования.
🟠JDBCAppender
Записывает логи в базу данных.
🚩Конфигурация Appender в log4j2
Вот пример конфигурации с использованием нескольких Appender
XML-конфигурация
Java-конфигурация
Ставь 👍 и забирай 📚 Базу знаний
Это компонент, который отвечает за отправку логов в различные места назначения, такие как файлы, консоль, базы данных, сетевые сокеты или даже удаленные серверы. Каждый Appender реализует конкретный способ обработки и хранения логов.
🚩Зачем нужен Appender?
Appender позволяет гибко управлять тем, куда и как сохраняются логи. В зависимости от требований приложения, вы можете:
Писать логи в файл.
Выводить их в консоль.
Отправлять их в удалённые хранилища или базы данных.
🚩Основные виды Appender в Log4j
🟠ConsoleAppender
Логи выводятся в консоль.
Полезно для разработки и отладки.
<Appender type="Console" name="ConsoleAppender">
<Target>System.out</Target>
</Appender>
🟠FileAppender
Логи записываются в файл.
Используется для длительного хранения логов.
<Appender type="File" name="FileAppender">
<FileName>logs/app.log</FileName>
<Append>true</Append>
</Appender>
🟠RollingFileAppender
Расширение FileAppender с возможностью ротации логов (ограничение размера файла, создание новых файлов при переполнении).
<Appender type="RollingFile" name="RollingFileAppender">
<FileName>logs/app.log</FileName>
<FilePattern>logs/app-%d{yyyy-MM-dd}.log</FilePattern>
<Policies>
<SizeBasedTriggeringPolicy size="10MB"/>
</Policies>
</Appender>
🟠DailyRollingFileAppender
Логи записываются в файл, который ротационно создаётся каждый день.
<Appender type="DailyRollingFile" name="DailyRollingAppender">
<FileName>logs/app.log</FileName>
<DatePattern>.yyyy-MM-dd</DatePattern>
</Appender>
🟠SocketAppender
Отправляет логи через сеть (TCP или UDP).
Используется для централизованного логирования.
🟠JDBCAppender
Записывает логи в базу данных.
<Appender type="JDBC" name="JDBCAppender">
<ConnectionSource>
<DriverManagerConnectionSource>
<DriverClass>org.h2.Driver</DriverClass>
<Url>jdbc:h2:mem:logdb</Url>
<User>sa</User>
</DriverManagerConnectionSource>
</ConnectionSource>
<TableName>log_table</TableName>
</Appender>
🚩Конфигурация Appender в log4j2
Вот пример конфигурации с использованием нескольких Appender
XML-конфигурация
<Configuration>
<Appenders>
<Console name="ConsoleAppender" target="SYSTEM_OUT">
<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss} [%t] %-5level: %msg%n"/>
</Console>
<File name="FileAppender" fileName="logs/app.log">
<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss} [%t] %-5level: %msg%n"/>
</File>
</Appenders>
<Loggers>
<Root level="info">
<AppenderRef ref="ConsoleAppender"/>
<AppenderRef ref="FileAppender"/>
</Root>
</Loggers>
</Configuration>
Java-конфигурация
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class Main {
private static final Logger logger = LogManager.getLogger(Main.class);
public static void main(String[] args) {
logger.info("This is an info log");
logger.error("This is an error log");
}
}
Ставь 👍 и забирай 📚 Базу знаний
👍4
🤔 Какая цель введения класса-обёрток?
- Превратить примитив в объект.
- Использовать с коллекциями (List<Integer>, нельзя List<int>).
- Участвовать в дженериках, быть null.
- Предоставить вспомогательные методы (parseInt, compareTo, toString).
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
- Превратить примитив в объект.
- Использовать с коллекциями (List<Integer>, нельзя List<int>).
- Участвовать в дженериках, быть null.
- Предоставить вспомогательные методы (parseInt, compareTo, toString).
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
👍13
🤔 Для чего нужен функциональный интерфейс BiConsumer<T,U>?
Сигнатура
🚩Вывод пар значений
Допустим, у нас есть
Вывод
🚩Использование `BiConsumer` в `Stream`
Допустим, у нас есть список продуктов и их цены. Мы хотим увеличить цену каждого товара и напечатать результат.
Вывод
🚩Объединение `BiConsumer` с `andThen()`
Метод
Вывод:
Ставь 👍 и забирай 📚 Базу знаний
BiConsumer<T, U> — это функциональный интерфейс из пакета java.util.function, который принимает два входных аргумента и не возвращает результат. Сигнатура
BiConsumer<T, U>@FunctionalInterface
public interface BiConsumer<T, U> {
void accept(T t, U u);
}
🚩Вывод пар значений
Допустим, у нас есть
Map<String, Integer>, и мы хотим вывести все ключи и значения: import java.util.Map;
import java.util.function.BiConsumer;
public class BiConsumerExample {
public static void main(String[] args) {
Map<String, Integer> map = Map.of("Alice", 30, "Bob", 25, "Charlie", 35);
// Используем BiConsumer для вывода ключа и значения
BiConsumer<String, Integer> printEntry = (key, value) ->
System.out.println("Имя: " + key + ", возраст: " + value);
// Применяем BiConsumer к каждому элементу Map
map.forEach(printEntry);
}
}
Вывод
Имя: Alice, возраст: 30
Имя: Bob, возраст: 25
Имя: Charlie, возраст: 35
🚩Использование `BiConsumer` в `Stream`
Допустим, у нас есть список продуктов и их цены. Мы хотим увеличить цену каждого товара и напечатать результат.
import java.util.*;
import java.util.function.BiConsumer;
public class BiConsumerStreamExample {
public static void main(String[] args) {
Map<String, Double> products = new HashMap<>();
products.put("Хлеб", 50.0);
products.put("Молоко", 80.0);
products.put("Яблоки", 120.0);
// BiConsumer, который увеличивает цену и выводит её
BiConsumer<String, Double> increaseAndPrint = (name, price) -> {
double newPrice = price * 1.1; // +10%
System.out.println(name + " теперь стоит " + newPrice);
};
products.forEach(increaseAndPrint);
}
}
Вывод
Хлеб теперь стоит 55.0
Молоко теперь стоит 88.0
Яблоки теперь стоят 132.0
🚩Объединение `BiConsumer` с `andThen()`
Метод
andThen(BiConsumer<T, U>) позволяет объединять несколько действий в цепочку. import java.util.function.BiConsumer;
public class BiConsumerChaining {
public static void main(String[] args) {
BiConsumer<String, Integer> printUser = (name, age) ->
System.out.println("Пользователь: " + name + ", возраст: " + age);
BiConsumer<String, Integer> checkAdult = (name, age) ->
System.out.println(name + (age >= 18 ? " совершеннолетний" : " несовершеннолетний"));
// Объединяем два BiConsumer'а
BiConsumer<String, Integer> combined = printUser.andThen(checkAdult);
combined.accept("Алексей", 20);
combined.accept("Мария", 16);
}
}
Вывод:
Пользователь: Алексей, возраст: 20
Алексей совершеннолетний
Пользователь: Мария, возраст: 16
Мария несовершеннолетний
Ставь 👍 и забирай 📚 Базу знаний
🔥6👍1
🤔 Что произойдёт, если в блоке инициализации возникнет исключительная ситуация?
Если исключение не обрабатывается, выполнение загрузки класса будет прервано, и он не сможет быть использован. Это приводит к системной ошибке на уровне JVM.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Если исключение не обрабатывается, выполнение загрузки класса будет прервано, и он не сможет быть использован. Это приводит к системной ошибке на уровне JVM.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
👍8🔥1💊1
🤔 Чем отличается обычный объект от Bean?
В Spring термин Bean (бин) означает объект, управляемый Spring-контейнером.
🟠Обычный объект (Java POJO)
Создаётся вручную, Spring о нём ничего не знает
🟠Spring Bean (управляемый объект)
Spring создаёт и управляет бином через аннотации.
Теперь объект создаётся Spring-контейнером
Ставь 👍 и забирай 📚 Базу знаний
В Spring термин Bean (бин) означает объект, управляемый Spring-контейнером.
🟠Обычный объект (Java POJO)
Создаётся вручную, Spring о нём ничего не знает
class Car {
void drive() {
System.out.println("Машина едет...");
}
}
public class Main {
public static void main(String[] args) {
Car car = new Car(); // Создаём объект вручную
car.drive();
}
}🟠Spring Bean (управляемый объект)
Spring создаёт и управляет бином через аннотации.
import org.springframework.stereotype.Component;
@Component // Сообщает Spring, что этот класс - Bean
class Car {
void drive() {
System.out.println("Spring-машина едет...");
}
}
Теперь объект создаётся Spring-контейнером
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class Main {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
Car car = context.getBean(Car.class); // Получаем Bean из Spring-контейнера
car.drive();
}
}
Ставь 👍 и забирай 📚 Базу знаний
8👍9
🤔 В чём смысл ReadWriteLock?
ReadWriteLock:
- Разделяет доступ на чтение и запись:
- Несколько потоков могут читать одновременно.
- Но только один поток может записывать (и блокирует чтение).
- Повышает производительность при преобладании операций чтения.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
ReadWriteLock:
- Разделяет доступ на чтение и запись:
- Несколько потоков могут читать одновременно.
- Но только один поток может записывать (и блокирует чтение).
- Повышает производительность при преобладании операций чтения.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
👍6🔥2
🤔 Почему строки так часто используют в виде ключей в HashMap?
Использование строк в качестве ключей в
🟠Строки неизменяемы
Что это значит: После создания строка не может быть изменена (все операции над строками создают новый объект).
Почему это важно: Ключ в
🟠Эффективный `hashCode` и `equals`
Что это значит: Класс
Почему это важно: Эти методы определяют, куда ключ попадет в
Особенность: Алгоритм
🟠Простота использования
Что это значит: Строки легко создавать, читать и понимать. Они часто используются для идентификаторов (например, имён, адресов, кодов).
Почему это важно: Программистам удобно использовать строки в качестве ключей, потому что их легко интерпретировать.
🟠Универсальность
Что это значит* Строки могут представлять самые разные данные — от имён и кодов до сложных текстовых идентификаторов.
Почему это важно: Почти любой объект или данные можно однозначно представить в виде строки, что делает её универсальным кандидатом на роль ключа.
🟠Широкая поддержка
Что это значит: Почти все приложения и API Java оперируют строками.
Почему это важно: Это упрощает интеграцию строк как ключей в сложных системах.
🚩Пример использования строки в качестве ключа
Ставь 👍 и забирай 📚 Базу знаний
Использование строк в качестве ключей в
HashMap очень распространено, потому что строки обладают рядом свойств, которые идеально подходят для этой задачи. Вот основные причины:🟠Строки неизменяемы
Что это значит: После создания строка не может быть изменена (все операции над строками создают новый объект).
Почему это важно: Ключ в
HashMap должен быть неизменяемым, потому что, если ключ изменится после его добавления, это нарушит работу хэш-таблицы. Например, HashMap больше не сможет найти объект по этому ключу.HashMap<String, Integer> map = new HashMap<>();
String key = "hello";
map.put(key, 1);
// key остается "hello", ничего не ломается
🟠Эффективный `hashCode` и `equals`
Что это значит: Класс
String в Java имеет качественно реализованные методы hashCode() и equals(), которые оптимизированы для работы с большими наборами данных.Почему это важно: Эти методы определяют, куда ключ попадет в
HashMap (по хэш-коду) и сравнивают ключи (по equals), чтобы избежать коллизий.Особенность: Алгоритм
hashCode() у строки быстро вычисляет хэш-код на основе её символов.String str1 = "hello";
String str2 = "hello";
System.out.println(str1.hashCode() == str2.hashCode()); // true
🟠Простота использования
Что это значит: Строки легко создавать, читать и понимать. Они часто используются для идентификаторов (например, имён, адресов, кодов).
Почему это важно: Программистам удобно использовать строки в качестве ключей, потому что их легко интерпретировать.
🟠Универсальность
Что это значит* Строки могут представлять самые разные данные — от имён и кодов до сложных текстовых идентификаторов.
Почему это важно: Почти любой объект или данные можно однозначно представить в виде строки, что делает её универсальным кандидатом на роль ключа.
🟠Широкая поддержка
Что это значит: Почти все приложения и API Java оперируют строками.
Почему это важно: Это упрощает интеграцию строк как ключей в сложных системах.
🚩Пример использования строки в качестве ключа
import java.util.HashMap;
public class Main {
public static void main(String[] args) {
HashMap<String, Integer> ageMap = new HashMap<>();
ageMap.put("Alice", 30);
ageMap.put("Bob", 25);
ageMap.put("Charlie", 35);
// Получаем значение по строковому ключу
System.out.println("Возраст Боба: " + ageMap.get("Bob")); // 25
}
}
Ставь 👍 и забирай 📚 Базу знаний
👍6
🤔 Что будет если в ApplicationContext попробуешь получить один и тот же бин?
Если бин имеет скоуп singleton (по умолчанию), ApplicationContext вернёт одну и ту же инстанцию бина при каждом запросе.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Если бин имеет скоуп singleton (по умолчанию), ApplicationContext вернёт одну и ту же инстанцию бина при каждом запросе.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
👍8
🤔 К какому принципу ООП относится переопределение методов?
Переопределение методов (Method Overriding) относится к полиморфизму – одному из ключевых принципов ООП.
🚩Как работает переопределение (`@Override`)?
Переопределение (
Используем полиморфизм
🚩Переопределение = полиморфизм времени выполнения (Runtime Polymorphism)
Перегрузка (
Переопределение (
🚩Когда нужно переопределять методы?
Когда подкласс должен изменить поведение родительского класса.
Когда работаем с абстрактными классами и интерфейсами.
Когда используем полиморфизм для гибкости кода.
Ставь 👍 и забирай 📚 Базу знаний
Переопределение методов (Method Overriding) относится к полиморфизму – одному из ключевых принципов ООП.
🚩Как работает переопределение (`@Override`)?
Переопределение (
Overriding) – это когда подкласс изменяет поведение метода родительского класса. class Animal {
void makeSound() {
System.out.println("Какое-то животное издаёт звук");
}
}
class Dog extends Animal {
@Override
void makeSound() {
System.out.println("Гав-гав!");
}
}
class Cat extends Animal {
@Override
void makeSound() {
System.out.println("Мяу!");
}
}Используем полиморфизм
public class Main {
public static void main(String[] args) {
Animal myAnimal = new Dog(); // Полиморфизм
myAnimal.makeSound(); // Выведет "Гав-гав!"
}
}🚩Переопределение = полиморфизм времени выполнения (Runtime Polymorphism)
Перегрузка (
Overloading) – полиморфизм времени компиляции (Compile-time). Переопределение (
Overriding) – полиморфизм времени выполнения (Runtime). 🚩Когда нужно переопределять методы?
Когда подкласс должен изменить поведение родительского класса.
Когда работаем с абстрактными классами и интерфейсами.
Когда используем полиморфизм для гибкости кода.
Ставь 👍 и забирай 📚 Базу знаний
👍8
Пожизненная PRO подписка на easyoffer по цене одного года.
Акция до 20 февраля. Покупаешь сейчас один раз – пользуешься всю жизнь без лимита, включая все будущие функции.
Запланированные новые фичи на ближайшие пол года:
1. Агрегатор вакансий
2. Улучшение резюме, чтобы проходить ATS системы
3. Генерация уникального резюме и сопроводительного письма под вакансию
Покупай на https://easyoffer.ru/
Акция до 20 февраля. Покупаешь сейчас один раз – пользуешься всю жизнь без лимита, включая все будущие функции.
Запланированные новые фичи на ближайшие пол года:
1. Агрегатор вакансий
2. Улучшение резюме, чтобы проходить ATS системы
3. Генерация уникального резюме и сопроводительного письма под вакансию
Покупай на https://easyoffer.ru/
🤔 Что находится внутри у HashSet и TreeSet?
- HashSet внутри использует HashMap. Элементы хранятся как ключи, а значения — фиктивные (Object PRESENT = new Object()).
- TreeSet основан на TreeMap, который реализован через самобалансирующееся красно-чёрное дерево. Элементы сортируются по Comparable или переданному Comparator.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
- HashSet внутри использует HashMap. Элементы хранятся как ключи, а значения — фиктивные (Object PRESENT = new Object()).
- TreeSet основан на TreeMap, который реализован через самобалансирующееся красно-чёрное дерево. Элементы сортируются по Comparable или переданному Comparator.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
👍8🔥4
🤔 Что лежит в основе Spring?
В основе фреймворка Spring лежит концепция инверсии управления (IoC, Inversion of Control) и внедрения зависимостей (DI, Dependency Injection). Эти принципы обеспечивают гибкость, расширяемость и удобство в управлении зависимостями между компонентами приложения, делая код более модульным, тестируемым и поддерживаемым.
🚩Инверсия управления (IoC)
Это парадигма, при которой контроль над выполнением программы частично или полностью передаётся фреймворку или библиотеке. В контексте Spring IoC означает, что сам фреймворк управляет созданием объектов и их жизненным циклом, а не программист напрямую. Это достигается через использование "контейнера IoC", который автоматически создаёт и связывает объекты в соответствии с конфигурацией приложения, заданной в XML-файлах, аннотациях или Java-конфигурации.
🚩Внедрение зависимостей (DI)
Это техника реализации IoC, при которой объектам "внедряются" или "предоставляются" их зависимости извне. Вместо того чтобы компоненты приложения самостоятельно создавали или искали необходимые им объекты (зависимости), Spring контейнер автоматически предоставляет им все необходимые зависимости в момент создания объекта. Это уменьшает связность между компонентами и упрощает управление зависимостями, а также их изменение и тестирование.
🚩Основные компоненты
🟠Spring Core Container
Включает в себя IoC и DI, обеспечивая основу для фреймворка.
🟠Spring AOP (Aspect-Oriented Programming)
Позволяет реализовывать поперечные задачи (например, логирование, транзакции) в виде аспектов, не изменяя основной бизнес-логики.
🟠Spring MVC
Фреймворк для создания веб-приложений по модели MVC.
🟠Spring Boot
Предоставляет набор инструментов для быстрой разработки и запуска приложений с минимальной конфигурацией.
🟠Spring Data
Упрощает доступ к данным, работу с базами данных и операциями CRUD.
🟠Spring Security
Предоставляет комплексные средства безопасности для аутентификации и авторизации.
Ставь 👍 и забирай 📚 Базу знаний
В основе фреймворка Spring лежит концепция инверсии управления (IoC, Inversion of Control) и внедрения зависимостей (DI, Dependency Injection). Эти принципы обеспечивают гибкость, расширяемость и удобство в управлении зависимостями между компонентами приложения, делая код более модульным, тестируемым и поддерживаемым.
🚩Инверсия управления (IoC)
Это парадигма, при которой контроль над выполнением программы частично или полностью передаётся фреймворку или библиотеке. В контексте Spring IoC означает, что сам фреймворк управляет созданием объектов и их жизненным циклом, а не программист напрямую. Это достигается через использование "контейнера IoC", который автоматически создаёт и связывает объекты в соответствии с конфигурацией приложения, заданной в XML-файлах, аннотациях или Java-конфигурации.
🚩Внедрение зависимостей (DI)
Это техника реализации IoC, при которой объектам "внедряются" или "предоставляются" их зависимости извне. Вместо того чтобы компоненты приложения самостоятельно создавали или искали необходимые им объекты (зависимости), Spring контейнер автоматически предоставляет им все необходимые зависимости в момент создания объекта. Это уменьшает связность между компонентами и упрощает управление зависимостями, а также их изменение и тестирование.
🚩Основные компоненты
🟠Spring Core Container
Включает в себя IoC и DI, обеспечивая основу для фреймворка.
🟠Spring AOP (Aspect-Oriented Programming)
Позволяет реализовывать поперечные задачи (например, логирование, транзакции) в виде аспектов, не изменяя основной бизнес-логики.
🟠Spring MVC
Фреймворк для создания веб-приложений по модели MVC.
🟠Spring Boot
Предоставляет набор инструментов для быстрой разработки и запуска приложений с минимальной конфигурацией.
🟠Spring Data
Упрощает доступ к данным, работу с базами данных и операциями CRUD.
🟠Spring Security
Предоставляет комплексные средства безопасности для аутентификации и авторизации.
Ставь 👍 и забирай 📚 Базу знаний
👍4
🤔 В чём разница между HashMap и WeakHashMap?
- HashMap удерживает ключи сильно → не GC;
- WeakHashMap — ключи GC-способны, могут быть удалены, если больше нигде не используются.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
- HashMap удерживает ключи сильно → не GC;
- WeakHashMap — ключи GC-способны, могут быть удалены, если больше нигде не используются.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
🔥9💊5👍4🤔1
🤔 Как устроена память JVM?
JVM (Java Virtual Machine) управляет памятью приложения и делит её на несколько областей.
🟠Heap (Куча) – область для объектов
Здесь хранятся ВСЕ объекты и массивы, созданные через
Управляется Garbage Collector (GC)
🟠Stack (Стек) – область для методов и переменных
Локальные переменные (
Ссылки на объекты в
Вызовы методов (кадры стека)
🟠Metaspace – метаданные классов
Хранит информацию о загруженных классах (названия, методы, поля, байт-код).
При загрузке нового класса
В Java 8 заменил устаревший
🟠Program Counter (PC Register)
Хранит адрес текущей инструкции, выполняемой потоком.
У каждого потока свой PC Register.
Работает как указатель в машинном коде.
🟠Native Method Stack
Хранит данные, связанные с вызовами нативных методов (
Если Java вызывает C++-код, информация о вызове хранится здесь.
Ставь 👍 и забирай 📚 Базу знаний
JVM (Java Virtual Machine) управляет памятью приложения и делит её на несколько областей.
🟠Heap (Куча) – область для объектов
Здесь хранятся ВСЕ объекты и массивы, созданные через
new. Управляется Garbage Collector (GC)
🟠Stack (Стек) – область для методов и переменных
Локальные переменные (
int, double, String – если не new) Ссылки на объекты в
Heap Вызовы методов (кадры стека)
public class StackExample {
public static void main(String[] args) {
int a = 5;
int b = sum(a, 10);
}
public static int sum(int x, int y) {
return x + y;
}
}🟠Metaspace – метаданные классов
Хранит информацию о загруженных классах (названия, методы, поля, байт-код).
При загрузке нового класса
ClassLoader выделяет память в Metaspace. В Java 8 заменил устаревший
PermGen. while (true) {
ClassLoader loader = new MyClassLoader();
Class<?> clazz = loader.loadClass("MyDynamicClass");
}🟠Program Counter (PC Register)
Хранит адрес текущей инструкции, выполняемой потоком.
У каждого потока свой PC Register.
Работает как указатель в машинном коде.
🟠Native Method Stack
Хранит данные, связанные с вызовами нативных методов (
JNI – Java Native Interface). Если Java вызывает C++-код, информация о вызове хранится здесь.
public class NativeExample {
public native void callCMethod();
}Ставь 👍 и забирай 📚 Базу знаний
👍11💊2
🤔 Каким образом передаются переменные в методы?
В Java всё передаётся по значению:
- Примитивы передаются как копии значений.
- Объекты — как копии ссылок, то есть метод работает с тем же объектом, но не может изменить саму ссылку.
Изменения внутри метода влияют на поля объекта, но не на саму переменную-ссылку.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
- Примитивы передаются как копии значений.
- Объекты — как копии ссылок, то есть метод работает с тем же объектом, но не может изменить саму ссылку.
Изменения внутри метода влияют на поля объекта, но не на саму переменную-ссылку.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
👍13
🤔 Массив — статическая структура данных или динамическая?
🟠Почему массив – статическая структура?
Фиксированный размер – при создании массива его длина задаётся раз и навсегда.
Нельзя изменить размер – нельзя добавить или удалить элементы после создания массива.
🟠Что делать, если нужен динамический массив?
В Java есть динамические структуры данных, например
Ставь 👍 и забирай 📚 Базу знаний
🟠Почему массив – статическая структура?
Фиксированный размер – при создании массива его длина задаётся раз и навсегда.
Нельзя изменить размер – нельзя добавить или удалить элементы после создания массива.
int[] numbers = new int[5]; // Размер 5, изменить нельзя!
🟠Что делать, если нужен динамический массив?
В Java есть динамические структуры данных, например
ArrayList. import java.util.ArrayList;
import java.util.List;
public class DynamicArrayExample {
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
System.out.println(list); // [1, 2, 3]
}
}
Ставь 👍 и забирай 📚 Базу знаний
👍3💊2
🤔 Почему появился HashMap?
HashMap решает задачи:
- Быстрого доступа к данным по ключу (в среднем за O(1)).
- Работает эффективнее, чем List или Set, при необходимости хранения пары ключ-значение.
- Позволяет гибко организовать кэш, справочники, индексированные хранилища.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
HashMap решает задачи:
- Быстрого доступа к данным по ключу (в среднем за O(1)).
- Работает эффективнее, чем List или Set, при необходимости хранения пары ключ-значение.
- Позволяет гибко организовать кэш, справочники, индексированные хранилища.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
💊9👍5