Какие виды JOIN есть? Спросят с вероятностью 19%.
JOIN — это способ объединения строк из двух или более таблиц на основе связанных между ними столбцов. Основные виды JOIN:
1️⃣ INNER JOIN
Возвращает строки, которые имеют совпадения в обеих таблицах. Если совпадений нет, строки не включаются в результат.
2️⃣ LEFT JOIN (или LEFT OUTER JOIN)
Возвращает все строки из левой таблицы и совпавшие строки из правой. Если совпадений нет, столбцы правой таблицы будут содержать NULL.
3️⃣ RIGHT JOIN (или RIGHT OUTER JOIN)
Возвращает все строки из правой таблицы и совпавшие строки из левой. Если совпадений нет, столбцы левой таблицы будут содержать NULL.
4️⃣ FULL JOIN (или FULL OUTER JOIN)
Возвращает строки, которые имеют совпадения в одной из таблиц. Если совпадений нет, столбцы не совпавшей таблицы будут содержать NULL.
5️⃣ CROSS JOIN
Возвращает декартово произведение всех строк из левой и правой таблиц. Может создать огромный результат, если таблицы большие.
6️⃣ SELF JOIN
Соединяет таблицу саму с собой, полезен для операций сравнения внутри одной таблицы.
Итого:
- INNER JOIN: Совпадения в обеих таблицах.
- LEFT JOIN: Все из левой + совпадения из правой.
- RIGHT JOIN: Все из правой + совпадения из левой.
- FULL JOIN: Совпадения или NULL, если нет совпадений.
- CROSS JOIN: Декартово произведение.
- SELF JOIN: Таблица соединяется сама с собой.
Выбирай нужный JOIN в зависимости от того, какие данные тебе нужны.
Java | Вопросы с собеседований
JOIN — это способ объединения строк из двух или более таблиц на основе связанных между ними столбцов. Основные виды JOIN:
1️⃣ INNER JOIN
Возвращает строки, которые имеют совпадения в обеих таблицах. Если совпадений нет, строки не включаются в результат.
SELECT Orders.OrderID, Customers.CustomerName
FROM Orders
INNER JOIN Customers ON Orders.CustomerID = Customers.CustomerID;
2️⃣ LEFT JOIN (или LEFT OUTER JOIN)
Возвращает все строки из левой таблицы и совпавшие строки из правой. Если совпадений нет, столбцы правой таблицы будут содержать NULL.
SELECT Orders.OrderID, Customers.CustomerName
FROM Orders
LEFT JOIN Customers ON Orders.CustomerID = Customers.CustomerID;
3️⃣ RIGHT JOIN (или RIGHT OUTER JOIN)
Возвращает все строки из правой таблицы и совпавшие строки из левой. Если совпадений нет, столбцы левой таблицы будут содержать NULL.
SELECT Orders.OrderID, Customers.CustomerName
FROM Orders
RIGHT JOIN Customers ON Orders.CustomerID = Customers.CustomerID;
4️⃣ FULL JOIN (или FULL OUTER JOIN)
Возвращает строки, которые имеют совпадения в одной из таблиц. Если совпадений нет, столбцы не совпавшей таблицы будут содержать NULL.
SELECT Orders.OrderID, Customers.CustomerName
FROM Orders
FULL JOIN Customers ON Orders.CustomerID = Customers.CustomerID;
5️⃣ CROSS JOIN
Возвращает декартово произведение всех строк из левой и правой таблиц. Может создать огромный результат, если таблицы большие.
SELECT Orders.OrderID, Customers.CustomerName
FROM Orders
CROSS JOIN Customers;
6️⃣ SELF JOIN
Соединяет таблицу саму с собой, полезен для операций сравнения внутри одной таблицы.
SELECT A.CustomerName AS CustomerName1, B.CustomerName AS CustomerName2
FROM Customers A, Customers B
WHERE A.CustomerID < B.CustomerID;
Итого:
- INNER JOIN: Совпадения в обеих таблицах.
- LEFT JOIN: Все из левой + совпадения из правой.
- RIGHT JOIN: Все из правой + совпадения из левой.
- FULL JOIN: Совпадения или NULL, если нет совпадений.
- CROSS JOIN: Декартово произведение.
- SELF JOIN: Таблица соединяется сама с собой.
Выбирай нужный JOIN в зависимости от того, какие данные тебе нужны.
Java | Вопросы с собеседований
Как связаны методы equals и hashCode в Java?
Спросят с вероятностью 12%
В Java методы equals() и hashCode() важны для правильной работы коллекций, особенно таких, как HashSet, HashMap, Hashtable и так далее. Эти методы есть у каждого объекта по умолчанию, но часто их нужно переопределить, чтобы всё работало как надо.
Метод equals()
Сравнивает два объекта и говорит, равны ли они. По умолчанию он просто проверяет, указывают ли две ссылки на один и тот же объект. Но часто его переопределяют, чтобы сравнивать объекты по значению их полей, а не по ссылкам.
Метод hashCode()
Возвращает целое число — хеш-код объекта. Этот код нужен для быстрого поиска объектов в хеш-таблицах. Он как бы представляет объект числом.
Как они связаны
1️⃣ Если два объекта равны по equals(), то их хеш-коды тоже должны быть равны. Это важно для хеш-таблиц, чтобы равные объекты попадали в одну "корзину".
2️⃣ Если хеш-коды двух объектов разные, значит и объекты точно не равны. Но если хеш-коды одинаковые, объекты могут быть как равны, так и не равны по equals() — это называется коллизией хеш-кодов.
Пример:
Когда переопределяешь equals(), обязательно переопредели и hashCode(), чтобы всё было правильно:
Соблюдение контрактов equals() и hashCode() гарантирует, что хеш-таблицы и другие коллекции, использующие хеширование, будут работать правильно и эффективно, избегая проблем и оптимизируя поиск и сравнение объектов.
Java | Вопросы с собеседований
Спросят с вероятностью 12%
В Java методы equals() и hashCode() важны для правильной работы коллекций, особенно таких, как HashSet, HashMap, Hashtable и так далее. Эти методы есть у каждого объекта по умолчанию, но часто их нужно переопределить, чтобы всё работало как надо.
Метод equals()
Сравнивает два объекта и говорит, равны ли они. По умолчанию он просто проверяет, указывают ли две ссылки на один и тот же объект. Но часто его переопределяют, чтобы сравнивать объекты по значению их полей, а не по ссылкам.
Метод hashCode()
Возвращает целое число — хеш-код объекта. Этот код нужен для быстрого поиска объектов в хеш-таблицах. Он как бы представляет объект числом.
Как они связаны
1️⃣ Если два объекта равны по equals(), то их хеш-коды тоже должны быть равны. Это важно для хеш-таблиц, чтобы равные объекты попадали в одну "корзину".
2️⃣ Если хеш-коды двух объектов разные, значит и объекты точно не равны. Но если хеш-коды одинаковые, объекты могут быть как равны, так и не равны по equals() — это называется коллизией хеш-кодов.
Пример:
Когда переопределяешь equals(), обязательно переопредели и hashCode(), чтобы всё было правильно:
public class Person {
private String name;
private int age;
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
return age == person.age && Objects.equals(name, person.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
}
Соблюдение контрактов equals() и hashCode() гарантирует, что хеш-таблицы и другие коллекции, использующие хеширование, будут работать правильно и эффективно, избегая проблем и оптимизируя поиск и сравнение объектов.
Java | Вопросы с собеседований
В чём различия StringBuilder и StringBuffer?
Спросят с вероятностью 12%
StringBuilder и StringBuffer используются для работы со строками, особенно когда нужно часто изменять их содержимое или динамически создавать строки. Они предлагают похожие методы, но главное различие между ними — это синхронизация и производительность.
StringBuffer
StringBuffer потокобезопасен, потому что все его методы синхронизированы. Это значит, что его можно безопасно использовать в многопоточных приложениях, где несколько потоков могут одновременно изменять один и тот же объект. Однако за эту безопасность приходится платить: синхронизация снижает производительность в однопоточных приложениях.
StringBuilder
StringBuilder не потокобезопасен, что делает его быстрее, чем StringBuffer в однопоточных приложениях. Если ты уверен, что объект будет использоваться только одним потоком, выбирай StringBuilder для лучшей производительности.
Сравнение производительности
В однопоточных приложениях StringBuilder быстрее, потому что ему не нужно тратить время на синхронизацию. В многопоточных приложениях выбирай StringBuffer для обеспечения безопасности данных.
Когда использовать что?
- StringBuilder: для однопоточных задач, где важна скорость.
- StringBuffer: для многопоточных задач, где нужна безопасность.
Примеры использования
StringBuilder:
StringBuffer:
Оба примера показывают, что StringBuilder и StringBuffer используются почти одинаково. Но выбор между ними зависит от того, нужно ли тебе обеспечить потокобезопасность или максимальную производительность.
Java | Вопросы с собеседований
Спросят с вероятностью 12%
StringBuilder и StringBuffer используются для работы со строками, особенно когда нужно часто изменять их содержимое или динамически создавать строки. Они предлагают похожие методы, но главное различие между ними — это синхронизация и производительность.
StringBuffer
StringBuffer потокобезопасен, потому что все его методы синхронизированы. Это значит, что его можно безопасно использовать в многопоточных приложениях, где несколько потоков могут одновременно изменять один и тот же объект. Однако за эту безопасность приходится платить: синхронизация снижает производительность в однопоточных приложениях.
StringBuilder
StringBuilder не потокобезопасен, что делает его быстрее, чем StringBuffer в однопоточных приложениях. Если ты уверен, что объект будет использоваться только одним потоком, выбирай StringBuilder для лучшей производительности.
Сравнение производительности
В однопоточных приложениях StringBuilder быстрее, потому что ему не нужно тратить время на синхронизацию. В многопоточных приложениях выбирай StringBuffer для обеспечения безопасности данных.
Когда использовать что?
- StringBuilder: для однопоточных задач, где важна скорость.
- StringBuffer: для многопоточных задач, где нужна безопасность.
Примеры использования
StringBuilder:
StringBuilder sb = new StringBuilder("Hello");
sb.append(" World");
System.out.println(sb.toString()); // Выводит "Hello World"
StringBuffer:
StringBuffer sb = new StringBuffer("Hello");
sb.append(" World");
System.out.println(sb.toString()); // Выводит "Hello World"
Оба примера показывают, что StringBuilder и StringBuffer используются почти одинаково. Но выбор между ними зависит от того, нужно ли тебе обеспечить потокобезопасность или максимальную производительность.
Java | Вопросы с собеседований
Что такое транзакция?
Спросят с вероятностью 12%
Транзакция в базах данных — это набор операций, который выполняется как единое целое. Она помогает сохранять целостность данных и соблюдает правила ACID (Atomicity, Consistency, Isolation, Durability), чтобы всё работало надёжно.
Основные свойства:
1️⃣ Атомарность (Atomicity): Всё или ничего. Если хоть одна часть транзакции не выполняется, откатывается всё, чтобы база данных вернулась к исходному состоянию.
2️⃣ Согласованность (Consistency): Транзакция переводит базу данных из одного согласованного состояния в другое, соблюдая все правила и ограничения.
3️⃣ Изоляция (Isolation): Операции одной транзакции изолированы от других до её завершения. Это предотвращает проблемы с параллельными транзакциями, например, когда одно изменение влияет на другое.
4️⃣ Долговечность (Durability): После завершения транзакции её результаты сохраняются в базе данных и не теряются даже при сбоях системы.
Пример:
Представьте, что вы переводите деньги с одного банковского счёта на другой. Транзакция будет выглядеть так:
1️⃣ Снять деньги со счёта отправителя.
2️⃣ Зачислить деньги на счёт получателя.
Обе операции должны выполниться вместе. Если что-то пошло не так и зачисление не удалось, снятие тоже должно быть отменено, чтобы деньги не исчезли.
Управление транзакциями:
Большинство баз данных поддерживают команды для работы с транзакциями:
- BEGIN TRANSACTION: Начало транзакции.
- COMMIT: Завершение транзакции и сохранение изменений.
- ROLLBACK: Отмена всех изменений, сделанных в рамках транзакции.
В итоге:
Транзакции — это способ гарантировать, что все операции с данными выполняются корректно и надёжно. Они позволяют уверенно выполнять сложные задачи с данными и обеспечивают их целостность.
Java | Вопросы с собеседований
Спросят с вероятностью 12%
Транзакция в базах данных — это набор операций, который выполняется как единое целое. Она помогает сохранять целостность данных и соблюдает правила ACID (Atomicity, Consistency, Isolation, Durability), чтобы всё работало надёжно.
Основные свойства:
1️⃣ Атомарность (Atomicity): Всё или ничего. Если хоть одна часть транзакции не выполняется, откатывается всё, чтобы база данных вернулась к исходному состоянию.
2️⃣ Согласованность (Consistency): Транзакция переводит базу данных из одного согласованного состояния в другое, соблюдая все правила и ограничения.
3️⃣ Изоляция (Isolation): Операции одной транзакции изолированы от других до её завершения. Это предотвращает проблемы с параллельными транзакциями, например, когда одно изменение влияет на другое.
4️⃣ Долговечность (Durability): После завершения транзакции её результаты сохраняются в базе данных и не теряются даже при сбоях системы.
Пример:
Представьте, что вы переводите деньги с одного банковского счёта на другой. Транзакция будет выглядеть так:
1️⃣ Снять деньги со счёта отправителя.
2️⃣ Зачислить деньги на счёт получателя.
Обе операции должны выполниться вместе. Если что-то пошло не так и зачисление не удалось, снятие тоже должно быть отменено, чтобы деньги не исчезли.
Управление транзакциями:
Большинство баз данных поддерживают команды для работы с транзакциями:
- BEGIN TRANSACTION: Начало транзакции.
- COMMIT: Завершение транзакции и сохранение изменений.
- ROLLBACK: Отмена всех изменений, сделанных в рамках транзакции.
В итоге:
Транзакции — это способ гарантировать, что все операции с данными выполняются корректно и надёжно. Они позволяют уверенно выполнять сложные задачи с данными и обеспечивают их целостность.
Java | Вопросы с собеседований
Может ли примитивный тип данных попасть в Heap?
Спросят с вероятностью 12%
Обычно примитивные типы данных (например, int, double) хранятся на стеке (stack), когда они определены как локальные переменные внутри методов. Но примитивы могут "попасть" в кучу (heap), когда они являются частью объекта или обернуты в специальные классы-обертки (Integer, Long, Double и т.д.), которые хранятся в куче.
Обертки примитивных типов
Каждый примитивный тип имеет свой класс-обертку. Например, int можно обернуть в Integer, а double — в Double. Когда примитив обернут в такой класс, он хранится в куче как часть объекта.
Примитивные типы как часть объектов
Если примитив является полем объекта, его значение будет храниться в куче вместе с этим объектом. Например, если у вас есть класс Person с полем int age, то значение age будет храниться в куче вместе с объектом Person.
Пример
В этом примере
Итог
Хотя примитивные типы данных обычно хранятся на стеке, они могут попасть в кучу, если являются частью объекта или обернуты в соответствующие классы-обертки. Это позволяет примитивам участвовать в динамическом управлении памятью и объектно-ориентированных структурах данных, сохраняя при этом эффективность работы с данными.
Java | Вопросы с собеседований
Спросят с вероятностью 12%
Обычно примитивные типы данных (например, int, double) хранятся на стеке (stack), когда они определены как локальные переменные внутри методов. Но примитивы могут "попасть" в кучу (heap), когда они являются частью объекта или обернуты в специальные классы-обертки (Integer, Long, Double и т.д.), которые хранятся в куче.
Обертки примитивных типов
Каждый примитивный тип имеет свой класс-обертку. Например, int можно обернуть в Integer, а double — в Double. Когда примитив обернут в такой класс, он хранится в куче как часть объекта.
Примитивные типы как часть объектов
Если примитив является полем объекта, его значение будет храниться в куче вместе с этим объектом. Например, если у вас есть класс Person с полем int age, то значение age будет храниться в куче вместе с объектом Person.
Пример
public class Person {
int age; // Примитивный тип данных внутри объекта, который хранится в куче
}
public class Main {
public static void main(String[] args) {
Integer number = 5; // Обертка для int, хранится в куче
Person person = new Person(); // Объект, хранящийся в куче, с примитивным полем
person.age = 25; // Примитивное значение age хранится в куче вместе с объектом person
}
}
В этом примере
number
(обернутый int) и person
(объект с полем age) хранятся в куче.Итог
Хотя примитивные типы данных обычно хранятся на стеке, они могут попасть в кучу, если являются частью объекта или обернуты в соответствующие классы-обертки. Это позволяет примитивам участвовать в динамическом управлении памятью и объектно-ориентированных структурах данных, сохраняя при этом эффективность работы с данными.
Java | Вопросы с собеседований