JavaRush /Java блог /Random UA /Розбір запитань та відповідей із співбесід на Java-розроб...
Константин
36 рівень

Розбір запитань та відповідей із співбесід на Java-розробника. Частина 6

Стаття з групи Random UA
Hello, World! Не переставати розвиватись дуже важливо для будь-якого розробника. Адже якщо зупинитися, є ризик стати незатребуваним і зовсім вилетіти з ринку: IT світ постійно розвивається та рухається вперед, і треба рухатися разом із ним. Але і при цьому не можна тільки зациклюватися тільки на нових і свіжих технологіях, щоб не забувати, так би мовити, про класику (класичні теми). Сьогодні я хочу продовжити свій розбір питань по “класичним” темам для Java-розробника. Розбір запитань та відповідей із співбесід на Java-розробника.  Частина 6 - 1Зазначу, що мої відповіді не є останньою інстанцією — це лише те, як я бачу правильні відповіді на ці запитання, і з чимось ви можете бути не згодні. Це буде цілком нормально, тому не соромтеся ділитися своєю думкою в коментарях. Посилання на частини розбору – наприкінці статті.Розбір запитань та відповідей із співбесід на Java-розробника.  Частина 6 - 2

Бібліотеки та стандарти

52. Що таке Hibernate? У чому різниця між JPA та Hibernate?

Я думаю, щоб відповісти на це питання, нам спочатку потрібно зрозуміти, що таке JPA . JPA - це специфікація, що описує об'єктно-реляційне відображення простих Java об'єктів і надає API для збереження, отримання та керування такими об'єктами. Тобто, як ми пам'ятаємо, реляційні бази даних (БД) представлені як безліч пов'язаних між собою таблиць. І JPA є загальноприйнятим стандартом, який описує, як об'єкти можуть взаємодіяти з реляційними базами даних. Як бачите, JPA - це щось абстрактне і невловиме. Це як би сама ідея, підхід. Розбір запитань та відповідей із співбесід на Java-розробника.  Частина 6 - 3У той же час, Hibernate — це конкретна бібліотека, що реалізує парадигми JPA.. Тобто за допомогою цієї бібліотеки ви можете працювати з реляційною базою даних через об'єкти, які представляють дані з БД (Entity). Як кажуть, ця бібліотека дуже близька до ідеалів JPA і можливо, тому вона стала популярною. А як ви розумієте, популярність використання — добрий аргумент для подальшої розробки та покращень. До того ж, за частим використанням стоїть величезне ком'юніті, яке розібрало вже всі можливі та неможливі питання, пов'язані з цим інструментом. Ось приклад книги , яка докладно розбирає всі темні закутки цієї технології. Тобто Hibernate максимально вивчений і, виходить, надійний. Власне, не дарма навіть ідеальна реалізація JPA з боку Spring-а під капотом зазвичай використовує Hibernate.

53. Що таке каскадність? Як вона використовується у Hibernate?

Як я і сказав раніше, Hibernate взаємодія ведеться через об'єкти даних, звані entity . Ці entity представляють якісь конкретні таблиці в базі даних, і як ви пам'ятаєте, Java класи можуть містити посилання на інші класи. Ці відносини відбиваються і базі даних. У БД, як правило, це зовнішні ключі (для OneToOne, OneToMany, ManyToOne), або проміжні таблиці (для ManyToMany) Детальніше про взаємозв'язок між сутностями можна почитати в цій статті . Коли у вашому entity є посилання інші зв'язані сутності, над цими посиланнями ставляться інструкції для вказівки типу зв'язку: @OneToOne, @OneToMany, @ManyToOne, @ManyToMane, у параметрах ви можете вказати значення властивості — cascade — тип каскаданості для цієї связи . УJPA є специфічні методи взаємодії з сутностями (persist, save, merge…). Каскадні типи використовуються для того, щоб показати, як повинні поводитися пов'язані дані при використанні цих методів на цільову сутність. Отже, які ж є стратегії каскаскадності (типи каскадності)? Стандарт JPA передбачає використання шести видів каскадності:
  • PERSIST — операції збереження відбуватимуться каскадно (для методів save() та persist() ). Тобто якщо ми зберігаємо сутність, пов'язану з іншими сутностями, вони також зберігаються в БД (якщо їх ще там немає)

  • MERGE — операції оновлення відбуватимуться каскадно (для методу merge() )

  • REMOVE - операції видалення відбуваються каскадно (метод remove() )

  • ALL - містить відразу три каскадні операції - PERSIST - MERGE - REMOVE

У JPA є поняття персистентна ( persistence ) сутність - сутність, пов'язана з її даними в БД, яка керується поточною сесією (сполукою). Якщо її змінити, але при цьому не зберегти зміни до БД, все одно її дані у БД будуть змінені.
  • DETACH - пов'язані сутності не керуватимуться сесією (метод detach() ). Тобто, при їх зміні не буде автоматичної зміни їх даних у БД - вони переводяться зі стану persistence в detached (сутність, не керована JPA)

  • REFRESH - при кожному оновленні сутності даними з БД ( refresh() - оновлює detached об'єкти) пов'язані сутності оновлюються так само. Наприклад, ви змінабо дані, взяті з БД, і хочете повернути їх початкові значення. У такому разі вам і знадобиться ця операція.

Розбір запитань та відповідей із співбесід на Java-розробника.  Частина 6 - 4Hibernate підтримує всі ці стандартні каскадні операції, але також привносить три свої:
  • REPLICATE — використовується, коли ми маємо більше одного джерела даних і ми хочемо, щоб дані синхронізувалися (метод Hibernate — replicate). У всіх сутностей повинні бути ідентифікатори (id), щоб не було проблем з їх генерацією (щоб для різних БД одна й та сама сутність не мала різних id)

  • SAVE_UPDATE — каскадне збереження/видалення (для Hibernate — saveOrUpdate )

  • LOCK - операція, зворотна до DETACHED : переводить detached сутність назад у стан persistence , тобто. entity стане знову відстежуваною поточною сесією

Якщо не вибрано тип каскадування, жодна операція з сутністю не матиме ефекту для пов'язаних з нею інших entity.

54. Чи може Entity клас бути абстрактним?

У специфікації JPA у пункті 2.1 The Entity Class є рядок: " І абстрактні, і конкретні класи можуть бути сутностями ". Тобто відповідь — так, абстрактний клас може бути сутністю і може бути анотований за допомогою @Entity.

55. Що таке entity manager? За що він відповідає?

В першу чергу хотілося б відзначити, що EntityManager - один із ключових компонентів JPA , який використовується для взаємодії сутностей із базою даних. Загалом методи взаємодії сутності з БД у нього і викликаються (persist, merge, remove, detach) ... Але також зазначу, що даний компонент як правило не є одним на все додаток: найчастіше він легковажний, часто видаляється і створюється новий за допомогою EntityManagerFactory . Якщо проводити паралель з JDBC , де EntityManagerFactory буде аналогом DataSource , то EntityManager у свою чергу буде аналогом Connection. Раніше я згадував про персистентну ( persistence ) сутність, як сутність, яка керується поточною сполукою. Так ось: ця сутність управляється саме EntityManager -ом, який тісно пов'язаний з поточним з'єднанням та TransactionManager -ом, який відповідає за відкриття/закриття транзакцій. Далі на малюнку нижче ви можете бачити життєвий цикл сутності:Розбір запитань та відповідей із співбесід на Java-розробника.  Частина 6 - 5EntityManager управляє сутністю, коли вона на етапі Managed (у цей час вона персистентна, тому що має зв'язок з EntityManager-ом). Тобто вона вже не new і ще не removed. Можна сміливо сказати, що коли сутність new чи removed, вона також і detached, т.к. вона не управляється EntityManager-ом. Існують різні стратегії для EntityManager-а. Тобто, може бути один синглтоновий EntityManager на всю програму, а може створюватися щоразу новий, під кожне з'єднання. Якщо ж ви використовуєте Spring, то управління створенням/видаленням EntityManager-а відбувається автоматично під капотом (але це не означає, що не можна налаштувати це під себе). Варто зазначити, що один або кілька членівадміністраторів і утворюють і послідовність контексту . Persistence context— це середовище, в якому екземпляри сутностей синхронізуються з аналогічними сутностями в базі даних (як я й казав, це працює тільки для персистентних сутностей). Якщо ви заглибитеся у вивчення JPA (що я дуже вам рекомендую), то з цим поняттям ви стикатиметеся дуже і дуже часто.

56. Що таке клас Assert? Для чого його використовувати?

У JPA я про такий клас не чув, тому припускаю, що тут мається на увазі клас JUnit бібліотеки, яка використовується для модульного тестування коду. Клас цієї бібліотеки, Assert , використовується для перевірки результатів виконання коду ( assert — твердження, що в певному місці у вас певний стан/дані). Наприклад, ви тестуєте метод, який має створювати кота. Ви запускаєте метод та отримуєте деякий результат:
Cat resultOfTest = createCat();
Але вам потрібно переконатися, що він був правильно створений, чи не так? Тому ви до цього створабо деякого кота — expectedCat — вручну з такими параметрами, які ви очікуєте від кота, отриманого з методу createCat() . Далі ви використовуєте клас Assert для звірки отриманих результатів:
Assert.assertEquals(resultOfTest, expectedCat);
Якщо коти будуть відрізнятися, буде викинуто виняток AssertionError , яке говорить нам про те, що очікувані результати не сходяться. У класу Assert є безліч різних методів, які покривають безліч завдань із перевірки очікуваних результатів. Ось деякі з них:
  • assertTrue(<boolean>) — очікуване значення, отримане як аргумент, має бути true

  • assertFalse(<boolean>) — очікуване значення, отримане як аргумент, має бути false

  • assertNotEquals(<object1>, <object2>) — об'єкти, отримані як аргументи, при порівнянні за допомогою equals повинні бути різними ( false )

  • assertThrows(<ClassNameOfException>.class, <exceptionObject>) — очікується, що другим аргументом буде виняток класу, прописаного першим аргументом (тобто, як правило, на місці другого аргументу викликається метод, який повинен кидати виняток потрібного типу)

String

57. Дайте характеристику String у Java

String - стандартний клас Java, що відповідає за зберігання і маніпуляції з рядковими значеннями (послідовності символів), є immutable класом (про immutable я писав раніше ), тобто. дані об'єктів цього класу неможливо змінити після створення. Хотілося б відразу відзначити, що класи StringBuilder і StringBuffer - це два фактично однакових класи з тією різницею, що один з них призначений для використання в багатопотоковому середовищі (StringBuffer). Ці класи є аналогами String , але на відміну від нього вони змінюються. Тобто об'єкти після створення допускають модифікацію рядка, який репрезентують, без створення нового об'єкта. Власне, методи відрізняються від стандартних методів String і спрямовані на задоволення потреб щодо зміни рядка (не дарма ж builder-ом назвали). Докладніше про String , StringBuffer та StringBuilder читайте ось у цій статті .

58. Які є способи створення об'єкта String? Де воно створюється?

Найзвичніший спосіб створення рядка – просте завдання потрібного нам значення у подвійних дужках:
String str = "Hello World!";
Також можна зробити це безпосередньо через new :
String str = new String("Hello World!");
Можна створити рядок та відштовхуючись від масиву символів:
char[] charArr = {'H','e','l','l','o',' ', 'W','o','r','l','d','!'};
String str = new String(charArr);
Як результат роботи методу toString на деякому об'єкті:
String str = someObject.toString();
Як результат роботи будь-якого іншого методу повертає рядкову виставу. Наприклад:
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
String str =  reader.readLine();
Як ви зрозуміли, способів створення рядка може бути дуже багато. При створенні об'єкта String він зберігається в рядковому пулі , про який докладніше ми поговоримо в одному з питань.

59. Як порівняти два рядки Java і як їх відсортувати?

Для порівняння значень Java використовується знак подвійного дорівнює == . Якби нам потрібно було порівнювати деякі прості значення на зразок int , ми б скористалися ним. Але для порівняння повноцінних об'єктів цей спосіб не застосовується. У такому разі це буде лише порівняння посилань — чи вказують вони на той самий об'єкт чи ні. Тобто при порівнянні двох об'єктів з абсолютно однаковими значеннями внутрішніх полів порівняння через == дасть результат false : незважаючи на однаковість полів об'єктів, об'єкти займають різні осередки пам'яті. А об'єкти класу String , незважаючи на оманливу простоту, все ж таки є об'єктами. І порівняння через ==для них також не застосовується (навіть незважаючи на наявність рядкового пулу). Тут за справу береться стандартний метод класу Object - equals , який необхідно перевизначити в класі для його коректної роботи (інакше за умовчанням він порівнює через == ). У класі String він перевизначений, отже, просто беремо і використовуємо його:
String firstStr = "Hello World!";
String secondStr = "Hello World!";
boolean isEquals = firstStr.equals(secondStr);
Розбір запитань та відповідей із співбесід на Java-розробника.  Частина 6 - 6Ми говорабо про порівняння на відповідність, тепер розберемо порівняння для сортування. Адже для сортування чогось потрібно знати, за яким принципом сортувати. Для цього можна скористатися стандартним відсортованим безліччю - TreeSet . Докладніше про різні колекції в Java ви можете почитати в цій статті . Даний список працює на основі алгоритму червоно-чорного дерева та сортує безліч відповідно до заданого принципу сортування. Як я й сказав раніше, треба розуміти, як відсортувати об'єкти певного типу. Для встановлення способу порівняння для сортування використовують компаратори . Як правило їх необхідно реалізовувати для класів, які ви хочете сортувати, але у випадку зі Stringвони вже реалізовані. Тому просто додаємо потрібні нам рядки в TreeSet , а він їх відсортує:
TreeSet<String> sortedSet = new TreeSet<>();
sortedSet.add("B");
sortedSet.add("C");
sortedSet.add("A");
sortedSet.forEach(System.out::println);
Висновок у консолі:
A B C

60. Наведіть алгоритм переведення рядка до символу. Напишіть відповідний код

Як я й говорив раніше, у об'єктів класу String дуже багато різних корисних методів. Один з таких - toCharArray . Даний метод переводить рядок у масив символів:
String str = "Hello world";
char[] charArr = str.toCharArray();
Далі ми маємо масив символів, які можемо викликати за індексом:
char firstChar = charArr[0]; // H

61. Як перевести рядок у масив байтів і назад? Напишіть відповідний код

Аналогічний метод toCharArray , клас String має метод getBytes , який повертає масив байтів рядка:
String str = "Hello world";
byte[] byteArr = str.getBytes();
byte firstChar = byteArr[6]; // 119
Сьогоднішня частина аналізу підійшла до логічного кінця. Дякую за увагу!Розбір запитань та відповідей із співбесід на Java-розробника.  Частина 6 - 7
Інші матеріали серії:
Коментарі
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ