Вопросы и информация для подготовки к собеседованию на должность разработчика Java

What are SOLID principles ?

What is Single Responsibility Principle (SRP):

A class should have only one responsibility.
It should have only one reason to change.
Benefits include easier testing, lower coupling, and better organization.
Пример:

Ява

public class Book {
private String name;
private String author;
private String text;
// constructor, getters, and setters
}

What is Open-Closed Principle (OCP):

Software entities (classes, modules, functions) should be open for extension but closed for modification.
Achieve this by using interfaces, abstract classes, and inheritance.
Пример:
Ява

Форма интерфейса {
двойная площадь();
}
class Circle implements Shape { /* implementation / } class Rectangle implements Shape { / implementation */ }

What is Liskov Substitution Principle (LSP):

Subtypes must be substitutable for their base types without altering the correctness of the program.
Follows the “is-a” relationship.
Пример:
Ява

class Bird { /* common bird behavior / } class Sparrow extends Bird { / specific sparrow behavior */ }

What is Interface Segregation Principle (ISP):

Clients should not be forced to depend on interfaces they don’t use.
Split large interfaces into smaller, more specific ones.
Пример:
Ява

interface Worker {
void work();
}
interface Eater {
недействительный съесть ();
}
класс Robot реализует Worker { /* реализация */ }

Что такое принцип инверсии зависимостей (DIP):

Модули высокого уровня не должны зависеть от модулей низкого уровня; оба должны зависеть от абстракций.
Абстракции не должны зависеть от деталей; детали должны зависеть от абстракций.

// Абстракция
интерфейс MessageSender {
void sendMessage (Строковое сообщение);
}

// Модуль высокого уровня
класс NotificationService {
личное MessageSender messageSender;

public NotificationService(MessageSender messageSender) {
this.messageSender = messageSender;
}
public void send(String message) {
messageSender.sendMessage(message);
}

}

// Модуль низкого уровня
класс EmailSender реализует MessageSender {
@Override
public void sendMessage (Строковое сообщение) {
System.out.println(“Отправка электронной почты: ” + сообщение);
}
}

// Еще один низкоуровневый модуль
класс SmsSender реализует MessageSender {
@Override
public void sendMessage (Строковое сообщение) {
System.out.println(“Отправка SMS: ” + сообщение);
}
}

// Основной класс
общественный класс Main {
public static void main(String[] args) {
// Используем отправитель электронной почты
MessageSender emailSender = новый EmailSender();
NotificationService NotificationService1 = новый NotificationService(emailSender);
NotificationService1.send(“Привет по электронной почте!”);

    // Use SmsSender
    MessageSender smsSender = new SmsSender();
    NotificationService notificationService2 = new NotificationService(smsSender);
    notificationService2.send("Hello via SMS!");
}

}

Интерфейс MessageSender служит абстракцией.
Модуль высокого уровня NotificationService зависит от этой абстракции, а не от конкретных реализаций.
Модули низкого уровня, такие как EmailSender и SmsSender, также зависят от абстракции, реализуя интерфейс MessageSender.

Что такое нормализация SQL

Что такое нормализация?
Нормализация включает в себя структурирование данных в реляционной базе данных для устранения таких аномалий, как избыточность.
Он разбивает большие и сложные таблицы на более мелкие, сохраняя при этом связи между данными.
Почему нормализация важна?
Уменьшает избыточность: разбивая данные на более мелкие таблицы, мы избегаем многократного хранения одной и той же информации.
Повышает производительность запросов. Нормализованные таблицы меньшего размера приводят к более быстрому выполнению запросов.
Минимизирует аномалии обновления: обновления можно вносить, не затрагивая другие записи.
Повышает целостность данных: обеспечивает согласованность и точность данных.
Сценарии нормализации:
Целостность данных: предотвращение несоответствий при обновлении данных (например, изменение возраста клиента).
Эффективные запросы: упростите сложные запросы за счет разбивки данных.
Оптимизация хранилища. Устраните ненужную избыточность для экономии места.

Что такое монолит микросервисов?

Что такое монолит?

Монолитное приложение строится как единое целое. Он тесно связывает все компоненты (такие как клиентский пользовательский интерфейс, база данных и серверное приложение) в одну базу кода.
Преимущества:
Простое развертывание: поскольку это один исполняемый файл или каталог, развертывание является простым.
Скорость разработки. На ранних этапах реализации проекта монолиты обеспечивают быструю разработку благодаря своей простоте.
Производительность: централизованный код может выполнять различные функции.

Что такое микросервисы?

Микросервисы разбивают приложение на более мелкие, независимо развертываемые сервисы. Каждая услуга ориентирована на конкретную сферу бизнеса.
Преимущества:
Масштабируемость: микросервисы позволяют масштабировать отдельные компоненты независимо.
Гибкость: разработчики могут выбирать разные технологии для каждого сервиса.
Изоляция: сбои в одной службе не влияют на другие.
Проблемы:
Сложность: управление несколькими сервисами требует надежной оркестрации.
Сетевые издержки: связь между службами приводит к задержке.
Сложность развертывания. Координация обновлений между службами может быть сложной задачей.

Что такое полиморфизм?

Переопределение метода:
Когда подкласс предоставляет конкретную реализацию метода, который уже определен в его суперклассе.

Перегрузка метода:
Когда класс имеет несколько методов с одинаковым именем, но разными параметрами (разное количество или типы аргументов).

Что используют частные конструкторы?

–Частные конструкторы используются в служебных классах или константных классах.
Эти классы содержат только статические методы или члены.

–Избежание создания подклассов

— Делегация конструктора:
Частные конструкторы позволяют делегировать конструкторы, когда определенные конструкторы вызывают общий частный конструктор.

— Одноэлементный шаблон

О JVM

–Компиляция:
Когда вы компилируете файл .java, компилятор Java создает файлы .class, содержащие байт-код (промежуточное представление).
Байт-код не зависит от платформы и может работать в любой системе с совместимой JVM.
–Подсистема загрузчика классов:
Отвечает за загрузку классов в память.
Считывает файлы .class, генерирует двоичные данные и сохраняет их в области метода.
Создает объект Class, представляющий загруженный класс в динамической памяти.
Пример: Студент s1 = новый Студент(); Класс c1 = s1.getClass();
–Связывание:
Состоит из трёх шагов:
Проверка: обеспечивает правильность файла .class.
Подготовка: выделяет память для переменных класса и инициализирует их.
Разрешение (необязательно): разрешает символические ссылки на другие классы или методы.
–Инициализация:
Выполняет статические инициализаторы (например, статические блоки) и инициализирует статические переменные.
Переменные экземпляра инициализируются при создании объекта.
— Механизм выполнения:
Преобразует байт-код в машинный код.
Включает JIT-компиляцию для оптимизации производительности.

— Короче говоря, JVM позволяет программам Java запускаться где угодно, интерпретируя байт-код и управляя памятью.

Что такое абстрактный метод Привата?

–Случаи использования частных методов в абстрактных классах:
Хотя абстрактные методы не могут быть частными, вы можете использовать частные методы внутри абстрактного класса для различных целей:
–Вспомогательные методы: реализуют общие функции, используемые другими методами.
–Инкапсуляция: скрыть детали реализации от подклассов.
–Классы, подобные структурам: создавайте небольшие классы с частными методами, которые служат контейнерами данных.

Что такое сборщик мусора?

–Кучная память:
Объекты Java создаются в куче — выделенной области памяти.
Некоторые объекты становятся недоступными (программа больше не ссылается на них).
–Сборщик мусора (GC):
GC идентифицирует и удаляет неиспользуемые объекты, чтобы освободить память.
Он запускается автоматически в фоновом режиме.
Два типа:
Второстепенный GC: удаляет недоступные объекты в молодом поколении.
Major GC (Full GC): Очищает объекты старого поколения.
–Преимущества:
Разработчикам не нужно явно удалять объекты.
GC обеспечивает доступность памяти и предотвращает ошибки OutOfMemoryErrors.

Что такое ООП?

Четыре принципа ООП:
–Инкапсуляция: объединение данных (атрибутов) и методов (функций) внутри класса, чтобы скрыть детали реализации и обеспечить понятный интерфейс.
–Наследование: создание новых классов на основе существующих, наследование их атрибутов и поведения. Это способствует повторному использованию кода.
–Полиморфизм: позволяет единообразно обрабатывать объекты разных классов через общий интерфейс. Это обеспечивает гибкость и расширяемость.
–Абстракция: сосредоточение внимания на основных функциях, скрытие ненужных сложностей. Абстракция упрощает дизайн и делает его более управляемым.

Что такое ACID-свойства играют решающую роль в обеспечении надежности и согласованности транзакций.

–Атомность:
Транзакции либо выполняются полностью, либо не выполняются вообще.
Отсутствие частичного выполнения: если транзакция завершается сбоем на полпути, любые изменения, внесенные в базу данных, откатываются.
Пример: рассмотрите возможность перевода 100 долларов США со счета X на счет Y. Если транзакция завершается неудачей после вычета из X, но до добавления в Y, база данных остается согласованной.
–Последовательность:
База данных должна поддерживать ограничения целостности до и после транзакции.
Пример: если общая сумма до транзакции составляет 700 долларов США (X: 500 долларов США, Y: 200 долларов США), она должна остаться прежней после транзакции (X: 400 долларов США, Y: 300 долларов США).
–Изоляция:
Несколько транзакций могут выполняться одновременно, не влияя друг на друга.
Изменения, внесенные одной транзакцией, не видны другим до тех пор, пока они не будут зафиксированы.
Обеспечивает эквивалентные результаты, как если бы транзакции выполнялись последовательно.
Пример: изоляция транзакций предотвращает несогласованность из-за чередующихся операций.
–Долговечность:
После фиксации транзакции ее изменения становятся постоянными.
Выдерживает системные сбои или сбои.
Обеспечивает постоянство данных.
Пример: даже после перезагрузки системы зафиксированные изменения остаются нетронутыми.
Помните, что свойства ACID обеспечивают основу для надежных и согласованных операций с базой данных! 🌟

Что такое шаблон стратегии?
Описание: Определяет семейство алгоритмов, инкапсулирует каждый из них и делает их взаимозаменяемыми. Это позволяет алгоритму изменяться независимо от клиентов, которые его используют.
Пример:
Ява

// Интерфейс пищевого поведения
интерфейс EatBehavior {
недействительный съесть ();
}

// Конкретные реализации пищевого поведения
класс NormalDiet реализует EatBehavior {
@Override
общественный недействительный съесть () {
// Нормальная еда
}
}

класс LosingWeightDiet реализует EatBehavior {
@Override
общественный недействительный съесть () {
// Здоровое питание
}
}

// Класс Cat с поведением при еде
абстрактный класс Cat {
EatBehavior eatBehavior;

public void eat() {
eatBehavior.eat();
}
public void setEatBehavior(EatBehavior eatBehavior) {
this.eatBehavior = eatBehavior;
}

}

// Использование
Кот кот = новый кот();
cat.setEatBehavior(новый LosingWeightDiet());
кот.есть(); // Кошка питается более здоровой пищей

Творческие шаблоны:
Эти шаблоны ориентированы на создание экземпляров классов.
Примеры включены

— Фабричный метод,
Постановка задачи. Предположим, мы хотим создавать различные типы продуктов (например, автомобили, велосипеды, велосипеды) без жесткой привязки нашего кода к конкретным реализациям.
Ключевые компоненты:
Продукт: абстрактный класс или интерфейс, определяющий общие операции для объектов, которые создаст фабрика.
Конкретные продукты: фактические классы, реализующие интерфейс продукта, представляющие определенные типы объектов.
Создатель: абстрактный класс или интерфейс, объявляющий фабричный метод. Он отвечает за создание объектов Product, но делегирует фактическое создание подклассам.
Конкретные создатели: подклассы создателя, реализующие фабричный метод. Они решают, какой конкретный конкретный продукт создать, на основе входных параметров или конфигурации.
Фабричный метод: метод, определенный в классе Creator, который создает объекты Product. Обычно он объявляется абстрактным в Creator и реализуется в Concrete Creators.
Пример на Java: допустим, у нас есть завод, производящий различные типы транспортных средств. Вот упрощенный пример:
Ява

// АннотацияПродукт
интерфейс продукта {
недействительный дисплей();
}

// Бетонные изделия
класс Car реализует Product {
публичный недействительный дисплей () {
System.out.println(“Машина создана”);
}
}

класс Bike реализует Product {
публичный недействительный дисплей () {
System.out.println(“Велосипед создан”);
}
}

// Создатель (Фабрика)
интерфейс Фабрика {
Фабрика продуктаМетод();
}

// Создатели бетона
класс ConcreteFactoryA реализует Factory {
публичный продукт FactoryMethod() {
вернуть новый автомобиль();
}
}

класс ConcreteFactoryB реализует Factory {
публичный продукт FactoryMethod() {
вернуть новый велосипед();
}
}

общественный класс FactoryMethodExample {
public static void main(String[] args) {
Фабрика FactoryA = новая ConcreteFactoryA();
Продукт ProductA = FactoryA.factoryMethod();
продуктA.display();

    Factory factoryB = new ConcreteFactoryB();
    Product productB = factoryB.factoryMethod();
    productB.display();
}

}

— Строитель
Шаблон «Строитель» — это креативный шаблон проектирования, который позволяет шаг за шагом создавать сложные объекты.
отделяя их построение от их представления. Вот простой пример на Java:
// Определите класс, который вы хотите создать
класс Сообщение {
частный финальный заголовок строки;
частный окончательный текст строки;
частная конечная строковая категория;

Post(Builder builder) {
this.title = builder.title;
this.text = builder.text;
this.category = builder.category;
}
// Getters for properties
public String getTitle() {
return title;
}
public String getText() {
return text;
}
public String getCategory() {
return category;
}
// Builder class
public static class Builder {
private String title;
private String text;
private String category;
public Builder title(String title) {
this.title = title;
return this;
}
public Builder text(String text) {
this.text = text;
return this;
}
public Builder category(String category) {
this.category = category;
return this;
}
public Post build() {
return new Post(this);
}
}

}

// Использование
общественный класс Main {
public static void main(String[] args) {
Сообщение сообщение = новый Post.Builder()
.title(“Шаблон Java Builder”)
.text(“Объясняем, как реализовать шаблон Builder в Java”)
.category(“Шаблоны проектирования”)
.строить();

    System.out.println("Title: " + post.getTitle());
    System.out.println("Text: " + post.getText());
    System.out.println("Category: " + post.getCategory());
}

}

–Прототип
Шаблон прототипа — это шаблон творческого проектирования, который позволяет создавать новые объекты путем копирования существующего объекта.
Вместо создания новых экземпляров с нуля вы клонируете существующий прототип, что может быть более эффективным и гибким. Давайте углубимся в пример на Java:
Определите интерфейс прототипа. Сначала мы создаем абстрактный класс или интерфейс под названием Tree с абстрактным методом copy():
Ява

публичное абстрактное дерево класса {
публичное абстрактное дерево copy();
}

Конкретные прототипы. Далее мы реализуем два конкретных класса, расширяющих Tree: PlasticTree и PineTree. Эти классы представляют определенные типы деревьев и предоставляют собственную реализацию метода copy():
Ява

общественный класс PlasticTree расширяет дерево {
@Override
копия публичного дерева() {
PlasticTree PlasticTreeClone = новый PlasticTree(this.getMass(), this.getHeight());
PlasticTreeClone.setPosition(this.getPosition());
вернуть пластикTreeClone;
}
}

общественный класс PineTree расширяет дерево {
@Override
копия публичного дерева() {
PineTree pineTreeClone = новый PineTree(this.getMass(), this.getHeight());
pineTreeClone.setPosition(this.getPosition());
вернуть pineTreeClone;
}
}
На этих занятиях мы настраиваем процесс клонирования в зависимости от конкретного типа дерева. Например, мы копируем массу, высоту и положение исходного дерева.
Использование: Теперь давайте создадим экземпляры наших конкретных прототипов:
Ява

общественный класс Main {
public static void main(String[] args) {
Дерево originalPlasticTree = новое PlasticTree(10, 5);
Дерево clonedPlasticTree = originalPlasticTree.copy();

    Tree originalPineTree = new PineTree(15, 8);
    Tree clonedPineTree = originalPineTree.copy();

    // Use the cloned trees as needed
    // ...
}

}

Что такое структурные закономерности?
Эти шаблоны касаются структуры и состава класса.

–Шаблон адаптера
Шаблон адаптера — это шаблон структурного проектирования, который позволяет обеспечить совместную работу двух несовместимых интерфейсов.
Он действует как мост между этими интерфейсами, обеспечивая совместную работу без изменения их исходного кода.

Адаптер объекта:
В этом подходе мы используем композицию для делегирования логики адаптеру.
Адаптер содержит Adaptee и делегирует метод request() методу specificRequest() в Adaptee.
Ява

// Адаптируемый (существующий класс)
класс Адаптер {
недействительный указанныйRequest() {
System.out.println(“Конкретный запрос Адаптируемого”);
}
}

// Целевой интерфейс
интерфейс Цель {
недействительный запрос();
}

// Адаптер (с использованием композиции)
Класс Адаптер реализует Target {
частный окончательный Адаптируемый Адаптируемый;

Adapter(Adaptee adaptee) {
this.adaptee = adaptee;
}
@Override
public void request() {
adaptee.specificRequest();
}

}

КлассАдаптер:
Требуется множественное наследование (в Java это невозможно).
Мы можем добиться этого, используя интерфейсы с методами по умолчанию.
Адаптер расширяет классы Target и Adaptee.
Ява

// Целевой интерфейс
интерфейс Цель {
недействительный запрос();
}

// Адаптируемый (существующий класс)
класс Адаптер {
недействительный указанныйRequest() {
System.out.println(“Конкретный запрос Адаптируемого”);
}
}

// Адаптер (с использованием наследования классов)
класс Adapter расширяет Adaptee реализует Target {
@Override
публичный недействительный запрос() {
указанныйЗапрос();
}
}
Преимущества и компромиссы:
Адаптер класса хорошо работает для сопоставления методов «один к одному».
Адаптер объектов обеспечивает большую гибкость и позволяет избежать модификации кода.

–Шаблон декоратора
Шаблон «Декоратор» — это креативный шаблон проектирования, который позволяет динамически добавлять функциональность и поведение объекта без дополнительных усилий.
влияя на поведение других существующих объектов внутри того же класса. Это особенно полезно, когда вы хотите расширить возможности объекта.
возможности без изменения его структуры.

Обзор:
Шаблон «Декоратор» обеспечивает расширенный интерфейс исходного объекта, наполняя его дополнительными функциями.
Мы предпочитаем композицию наследованию, чтобы уменьшить накладные расходы на создание подклассов.
Декораторы можно добавлять во время выполнения, что обеспечивает гибкость.
Пример сценария: предположим, что у нас есть объект «Рождественская елка», и мы хотим украсить его различными предметами, такими как гирлянды, мишура и гирлянды. Мы будем следовать оригинальным правилам дизайна «Банды четырех»:
Выполнение:
Сначала создайте интерфейс ChristmasTree:
Ява

общедоступный интерфейс
Украшение строки();
}

Реализуйте интерфейс с помощью базового дерева:
Ява

публичный класс ChristmasTreeImpl реализует ChristmasTree {
@Override
публичная строка украсить() {
вернуть «Ёлку»;
}
}

Затем создайте абстрактный класс TreeDecorator, который реализует ChristmasTree и содержит украшенное дерево:
Ява

публичный абстрактный класс TreeDecorator реализует ChristmasTree {
частная последняя рождественская елка;

public TreeDecorator(ChristmasTree tree) {
this.tree = tree;
}
@Override
public String decorate() {
return tree.decorate();
}

}

Теперь создайте конкретные декораторы. Например, BubbleLights:
Ява

общественный класс BubbleLights расширяет TreeDecorator {
public BubbleLights (елка ChristmasTree) {
супер(дерево);
}

@Override
public String decorate() {
return super.decorate() + " with Bubble Lights";
}

}

публичный класс Garland расширяет TreeDecorator {
общественная гирлянда (елка ChristmasTree) {
супер(дерево);
}

@Override
public String decorate() {
return super.decorate() + " with Garland";
}

}
Использование:
Создайте украшенные деревья:
Ява

общественный класс DecoratorPatternDemo {
public static void main(String[] args) {
ChristmasTree Tree1 = новая гирлянда (новая ChristmasTreeImpl());
System.out.println(tree1.decorate()); // Вывод: «Рождественская елка с гирляндой»

    ChristmasTree tree2 = new BubbleLights(new Garland(new Garland(new ChristmasTreeImpl())));
    System.out.println(tree2.decorate()); // Output: "Christmas tree with Garland with Garland with Bubble Lights"
}

}
Шаблон позволяет добавлять декораторы во время выполнения, обеспечивая гибкость при необходимости декорирования.
Помните, что шаблон «Декоратор» широко используется в сценариях, где вы хотите улучшить поведение объекта без изменения его базовой структуры.

— Фасадный узор
Шаблон «Фасад» — это шаблон структурного проектирования, который упрощает взаимодействие со сложной подсистемой, предоставляя унифицированный интерфейс.
Он действует как «парадная дверь», скрывая основную сложность и облегчая клиентам использование системы.

–Композитный
Составной шаблон — это структурный шаблон проектирования, который позволяет объединять объекты в древовидные структуры для представления иерархий «частичное целое».
Основная идея составного шаблона заключается в построении древовидной структуры объектов, в которой отдельные объекты и составные объекты имеют общий интерфейс.

Базовый компонент (отдел). В качестве базового компонента мы определим простой интерфейс отдела:
Ява

Отдел публичного интерфейса {
void printDepartmentName();
}

Конечные компоненты (FinancialDepartment и SalesDepartment): давайте создадим классы для финансового отдела и отдела продаж, оба реализующие интерфейс Department:
Ява

публичный класс FinancialDepartment реализует Department {
// Детали реализации (например, идентификатор, имя)
общественный недействительный printDepartmentName () {
System.out.println(getClass().getSimpleName());
}
}

публичный класс SalesDepartment реализует Department {
// Детали реализации (например, идентификатор, имя)
общественный недействительный printDepartmentName () {
System.out.println(getClass().getSimpleName());
}
}

Эти конечные классы реализуют метод printDepartmentName() и не содержат ссылок на другие объекты отдела.
Составной элемент (HeadDepartment). В качестве составного класса давайте создадим HeadDepartment, содержащий коллекцию компонентов отдела:
Ява

импортировать java.util.ArrayList;
импортировать java.util.List;

публичный класс HeadDepartment реализует Department {
частный целочисленный идентификатор;
private String name;
частный список дочерних отделов;

public HeadDepartment(Integer id, String name) {
this.id = id;
this.name = name;
this.childDepartments = new ArrayList<>();
}
public void printDepartmentName() {
childDepartments.forEach(Department::printDepartmentName);
}
public void addDepartment(Department department) {
childDepartments.add(department);
}
public void removeDepartment(Department department) {
childDepartments.remove(department);
}

}

Класс HeadDepartment реализует метод printDepartmentName() и предоставляет методы для добавления и удаления дочерних отделов.
Использование: Вы можете создавать экземпляры конечных отделов (например, FinancialDepartment, SalesDepartment) и составной отдел (например, HeadDepartment). Добавьте в композицию листовые отделы и выведите их названия.
Ява

общественный класс Main {
public static void main(String[] args) {
Финансы отдела = новый FinancialDepartment();
Отдел продаж = новый отдел продаж();

    HeadDepartment headDepartment = new HeadDepartment(1, "Company Departments");
    headDepartment.addDepartment(finance);
    headDepartment.addDepartment(sales);

    headDepartment.printDepartmentName();
}

}

Выход:
ФинансовыйОтдел
Отдел продаж

Составной шаблон позволяет создавать гибкие древовидные структуры, в которых
отдельные объекты и композиции (композиты) можно рассматривать единообразно.

Что такое ХЭШ-функция!!!

Хэш-функция — это математическая функция, которая принимает входные данные (или «сообщение») и возвращает строку символов фиксированного размера.
который обычно представляет собой последовательность цифр и букв. Этот результат называется «хеш-значением» или просто «хешем».
Хэш-функции обычно используются в информатике и криптографии и имеют несколько важных свойств:

=== Как бы вы использовали хеш-функцию и как она работает?

Детерминированный: одни и те же входные данные всегда будут давать один и тот же хэш.

Быстро: функция может быстро вычислить хэш-значение для любого заданного ввода.
Уникальный (почти): два разных входа должны давать разные хэши (это называется минимизацией «коллизий»).
Необратимость: учитывая хэш, вычислительно невозможно определить исходные входные данные.
Равномерность: хеш-значения равномерно распределены по выходному пространству.

Хэш-функции широко используются в различных приложениях, таких как:

Целостность данных. Чтобы гарантировать, что данные не были изменены или подделаны, путем сравнения значений хеш-функции.
Хранение паролей: безопасное хранение хешированных паролей вместо реальных паролей.
Криптография: используется в цифровых подписях и других криптографических алгоритмах.
Хэш-таблицы: для эффективного поиска данных в программировании.

=== Приведите мне пример хэш-карты, как бы вы ее использовали?

SHA (алгоритм безопасного хеширования):
Включает такие варианты, как SHA-1, SHA-256, SHA-384 и SHA-512.
SHA-256 и SHA-512 широко используются в криптографии и технологии блокчейна (например, Биткойн).

импортировать java.security.MessageDigest;
импортировать java.security.NoSuchAlgorithmException;

общественный класс HashExample {
public static void main(String[] args) {
пытаться {
// Входная строка, которую нужно хешировать
String input = “Привет, мир!”;

        // Create a MessageDigest instance for SHA-256
        MessageDigest digest = MessageDigest.getInstance("SHA-256");

        // Compute the hash
        byte[] hash = digest.digest(input.getBytes());

        // Convert the hash bytes to a hexadecimal string
        StringBuilder hexString = new StringBuilder();
        for (byte b : hash) {
            String hex = String.format("%02x", b);
            hexString.append(hex);
        }

        // Print the resulting hash
        System.out.println("SHA-256 Hash: " + hexString.toString());
    } catch (NoSuchAlgorithmException e) {
        System.err.println("Error: " + e.getMessage());
    }
}

}

Входные данные: входная переменная содержит данные, которые вы хотите хэшировать.
Инициализация MessageDigest: Экземпляр MessageDigest создается с помощью getInstance(“SHA-256”), который определяет алгоритм хеширования SHA-256.
Хеширование: метод дайджеста вычисляет хэш входных данных.
Шестнадцатеричное преобразование. Поскольку хэш имеет двоичный формат, мы используем цикл для его преобразования в более читаемую шестнадцатеричную строку.

Поставить и пропатчить? Когда его использовать?

И PUT, и PATCH — это методы HTTP, используемые для обновления ресурсов на сервере, но они различаются по способу обработки обновлений:

ПОМЕЩАТЬ:
Полное обновление:
PUT используется для полной замены существующего ресурса.
В запросе необходимо отправить весь ресурс, даже если меняется только его часть.

Если ресурс не существует, PUT часто создает его (хотя такое поведение может различаться).

Идемпотент:

Повторные запросы PUT с одними и теми же данными всегда будут приводить к одному и тому же состоянию ресурса.
Пример: Обновление профиля пользователя:

JSON
ПОМЕСТИТЕ /пользователи/123
{
“name”: “Велислав”,
“электронная почта”: “velislav@example.com”,
«возраст»: 30
}
Если меняется только имя, но адрес электронной почты и возраст остаются прежними, их все равно необходимо включить в запрос.

ПАТЧИ:
Частичное обновление:

PATCH используется для частичного обновления существующего ресурса.
В запросе необходимо отправлять только изменяемые поля.

Идемпотент (в основном):

Как и PUT, повторные запросы PATCH с одними и теми же данными обычно приводят к одному и тому же состоянию ресурса.
Однако поведение может зависеть от реализации сервера.

Пример: Обновление только имени пользователя:

JSON
ПАТЧ /пользователи/123
{
“name”: “Велислав”
}
Здесь обновляется только поле имени, остальные поля остаются неизменными.

Ключевое отличие:
PUT заменяет весь ресурс, а PATCH изменяет только указанные поля ресурса.

HTTP-методы с кратким описанием.

GET: используется для получения данных с сервера без их изменения. Обычно используется для получения ресурсов или информации.
POST: используется для отправки данных на сервер, обычно для создания нового ресурса. Например, отправка формы или загрузка файла.
PUT: используется для обновления или полной замены существующего ресурса на сервере. Если ресурс не существует, его можно создать.
ИСПРАВЛЕНИЕ: используется для частичного обновления существующего ресурса, изменяя только указанные поля.
УДАЛЕНИЕ: используется для удаления ресурса с сервера.
HEAD: аналогично GET, используется для получения заголовков без тела ресурса.
ОПЦИИ: сообщает, какие методы HTTP разрешены.
TRACE: используется в основном в диагностических целях путем возврата запроса клиенту.
ПОДКЛЮЧЕНИЕ: устанавливает туннель к серверу, часто используемый для соединений SSL/TLS.

========== Функциональный интерфейс ==================================

Функциональный интерфейс в Java — это интерфейс, содержащий ровно один абстрактный метод. Эти интерфейсы используются в основном в лямбда-выражениях и ссылках на методы, что обеспечивает более краткое и читаемое функциональное программирование.

Ключевые особенности:

  1. Одиночный абстрактный метод: Функциональный интерфейс имеет только один абстрактный метод. В этом суть его функциональности.
  2. Стандартные и статические методы: Функциональные интерфейсы могут включать методы по умолчанию и статические методы, но они не считаются одним абстрактным методом.
  3. Аннотация @FunctionalInterface: Хотя эта аннотация необязательна, она помогает, сигнализируя о том, что интерфейс задуман как функциональный. Если в интерфейс добавляются дополнительные абстрактные методы, компилятор выдает ошибку.

Пример:

@FunctionalInterface
interface Calculator {
int calculate(int a, int b);
}
// Using lambda expression
public class Main {
public static void main(String[] args) {
// Implementing the calculate method using a lambda
Calculator addition = (a, b) -> a + b;
Calculator multiplication = (a, b) -> a * b;
System.out.println("Addition: " + addition.calculate(5, 3)); // Output: 8
System.out.println("Multiplication: " + multiplication.calculate(5, 3)); // Output: 15
}
}

Вариант использования:

The Calculator интерфейс в примере имеет один абстрактный метод calculate, что делает его функциональным интерфейсом.
Это позволяет нам использовать лямбда-выражения для краткости и элегантности реализации.

Общие функциональные интерфейсы в Java:

Java предоставляет несколько встроенных функциональных интерфейсов в java.util.function пакеты, такие как:

  • Предикат: принимает входные данные и возвращает логическое значение.
  • Функция: принимает входные данные и возвращает выходные данные типа R.
  • Поставщик: Предоставляет значение без ввода.
  • Потребитель: принимает значение и выполняет действие.

Функциональные интерфейсы упрощают операции, особенно в таких сценариях, как работа с коллекциями, потоками или асинхронными задачами.

Они позволяют Java применять парадигмы функционального программирования, сохраняя при этом свою объектно-ориентированную природу.

================ Функция высшего порядка ===========================
Функция высшего порядка — это функция, которая либо принимает другие функции в качестве аргументов, либо возвращает функцию в качестве результата. Другими словами, он оперирует функциями, обращаясь с ними как с «гражданами первого сорта». Это мощная функция в парадигмах функционального программирования, позволяющая абстрагировать, повторно использовать код и композицию.

Пример функции высшего порядка в Java:

import java.util.function.Function;
public class Main {
public static void main(String[] args) {
// Higher-order function: applies a function to a value
Function<Integer, Integer> squareFunction = x -> x * x;
int result = applyFunction(5, squareFunction);
System.out.println("Square of 5: " + result); // Output: 25
}
public static int applyFunction(int value, Function<Integer, Integer> function) {
return function.apply(value);
}
}

В примере выше:

  • The applyFunction метод является функцией более высокого порядка, поскольку он принимает другую функцию (Function<Integer, Integer>) в качестве параметра.

Функции:

  1. Принимает функции в качестве аргументов: функции высшего порядка могут принимать другие функции в качестве входных данных для выполнения определенных операций.
  2. Возвращает функции: они могут динамически генерировать и возвращать новые функции.
  3. Поощряет повторное использование кода: продвигает модульный и повторно используемый код, поскольку функции можно передавать и составлять вместе.

Вариант использования:

В Java функции высшего порядка обычно используются в функциональном программировании с потоками, лямбда-выражениями и ссылками на методы. Например:

List<String> names = Arrays.asList("John", "Jane", "Jake");
names.stream()
.filter(name -> name.startsWith("J")) // Takes a lambda function as argument
.forEach(System.out::println); // Takes a method reference as argument

Функции высшего порядка придают Java-программам гибкость и мощь, позволяя разработчикам писать чистый, краткий и выразительный код!

Здесь приведены ответы на некоторые реальные интервью.

  • Понимает основы, такие как полиморфизм, статические методы и пул строк.
  • знакомы с коллекциями (например, HashSet, TreeSet) и вариантами их использования.
  • Правильно идентифицирует области bean-компонентов (синглтон, прототип).
  • Понимание внедрения зависимостей и его цели.
  • знает, как реализовать отношения «многие ко многим» с помощью соединительных таблиц.
  • Понимает назначение индексов (хотя и поверхностно)
  • может различать монолитную и микросервисную архитектуру
  • понимает основные компромиссы (масштабируемость, ремонтопригодность)
  • неправильно понимает принцип замены Лискова и инверсию зависимостей
  • Пытается предоставить конкретные примеры принципа открытости/закрытости.
  • Не хватает глубины в управлении жизненным циклом компонентов.
  • Неясно о расширенном внедрении зависимостей
  • поверхностное понимание индексов (составные индексы, оптимизация запросов)
  • Незнаком с уровнями изоляции и оптимистичной/пессимистической блокировкой.

Плюсы:

  • Работал с устаревшим кодом в огромной и сложной системе.
  • Знает SOLID
  • Знание потоков
  • Объясненные индексы и ACID
  • Хороший уровень английского языка
    Минусы:
  • Никакой ответственности за развертывание или инфраструктуру, участие в проектировании архитектуры.
  • Имеет некоторые знания принципов ООП, но ему очень сложно их объяснить, и он неправильно понял некоторые концепции.
  • Общие знания о коллекциях, но есть пробелы и очень неопределенные
  • Не понимает разницы между параллелизмом и параллелизмом, не очень глубокие знания в области параллелизма.
  • Не особо вникал в микросервисную архитектуру.
  • Неопределенность некоторых концепций баз данных (обсуждение индексов носило поверхностный характер)
  • Не могу объяснить живую блокировку
  • Пробелы в конечном итоге блокируют понимание
  • Ограниченное знание особенностей обработки исключений.
  • Запутались в модификаторах доступа (Защищенный или Частный пакет)
    Консенсусное мнение…..является
    не подходит на должность Mid-Java разработчика из-за пробелов в технических знаниях.

Плюсы
ТОЧНО хорошо объяснил
Хорошо объяснил ООП
Объяснил состав (но поначалу немного затруднился)
Отличное понимание коллекций
Разница между списками и наборами
Хэшсеты
Хэшмап
Параллельная хеш-карта
Хорошее понимание структур данных – стеки, очереди, деревья.
Хорошее знание JVM-архитектуры.
Объяснил параллелизм и параллелизм, продемонстрировал хорошее знание многопоточных приложений.
Хорошее понимание REST
Хорошо объяснил индексы БД
Объяснение различных типов соединений.

Оставить ответ

Узнайте больше из блога Велислава Крастева

Подпишитесь сейчас, чтобы продолжить чтение и получить доступ к полному архиву.

Продолжить чтение