Наведені питання допоможуть вам освіжити знання перед співбесідою, або почерпнути щось нове. Для отримання практичних навичок займайтеся на JavaRush .
-
Як створити незмінний об'єкт у Java? Перерахуйте всі переваги
Незмінний клас – це клас, стан якого може бути змінено після створення. Тут станом об'єкта по суті вважаються значення, що зберігаються в екземплярі класу, будь то примітивні типи або типи посилань.
Для того щоб зробити клас незмінним, необхідно виконати такі умови:
- Не надавайте сеттери або методи, які змінюють поля або об'єкти, що посилаються на поля. Сетери мають на увазі зміну стану об'єкта, а це те, чого ми хочемо тут уникнути.
- Зробіть всі поля
finalтаprivate. Поля, позначеніprivate, будуть недоступними зовні класу, а позначення їхfinalгарантує, що ви не зміните їх випадково. - Не дозволяйте субкласам перевизначати методи. Найпростіший спосіб це зробити – оголосити клас як
final. Фіналізовані класи Java не можуть бути перевизначені. - Завжди пам'ятайте, що ваші екземпляри змінних можуть бути змінюваними або незмінними. Визначте їх та повертайте нові об'єкти з скопійованим вмістом для всіх змінних об'єктів (посилальні типи). Змінні змінні (примітивні типи) можуть бути безпечно повернені без додаткових зусиль.
Також, вам необхідно пам'ятати наступні переваги незмінних класів. Можливо, вони знадобляться вас на співбесіді. Незмінні класи:
- легко конструювати, тестувати та використовувати
- автоматично потокобезпечні та не мають проблем синхронізації
- не вимагають конструктора копіювання
- дозволяють виконати «ліниву ініціалізацію» хешкода і кешувати значення, що повертається
- не вимагають захищеного копіювання, коли використовуються як поле
- роблять хороші
Mapключі таSetелементи (ці об'єкти не повинні змінювати стан, коли знаходяться в колекції) - роблять свій клас постійним, одного разу створивши його, а він не потребує повторної перевірки
- завжди мають «атомарність по відношенню до збою» (failure atomicity, термін застосував Джошуа Блох): якщо незмінний об'єкт кидає виняток, він ніколи не залишиться у небажаному чи невизначеному стані.
Подивіться приклад, написаний у цьому пості .
-
У Java передача за значенням чи за посиланням?
Java специфікація свідчить, що це Java передається за значенням. Немає такого поняття, як «передача за посиланням» Java. Ці умови пов'язані з викликом методів і передачі змінних, як параметрів методу. Добре, примітивні типи завжди передаються за значенням без будь-якої плутанини. Проте, концепція має бути зрозумілою у контексті параметра методу складних типів.
У Java, коли ми передає посилання складного типу як будь-який параметр методу, завжди адресаа пам'яті копіюється в нову змінну змінну крок за кроком. Подивіться на зображення:
У наведеному прикладі, біти адресаи першого екземпляра копіюються інший посилальної змінної, в результаті чого обидві посилання вказують на одну ділянку пам'яті, де зберігається об'єкт. Пам'ятайте, що привласнивши друге посилання null, ви не надасте null першому посиланні. Але зміна стану об'єкта з однією змінною, що посилається, буде відображено і в іншому посиланні.
Подробиці дивіться тут .
-
Яке застосування блоку
finally? Чи гарантує цей блок виконання свого коду? Колиfinallyблок не викликається?Блок
finallyзавжди викликається, якщоtryє блок. Це гарантує, що блокfinallyвикликається навіть якщо трапляється несподіваний виняток. Алеfinallyє більш корисним, ніж просто для обробки винятків – цей блок дозволяє виконати чищення коду, який випадково обійшов черезreturn,continueабоbreak. Розміщення коду, що очищає, в блокfinallyзавжди є хорошою практикою, навіть коли не очікується жодних винятків.Якщо віртуальна машина завершує роботу під час виконання блоку
tryабоcatch, тоді блокfinallyне буде виконано. Аналогічно, якщо нитка, виконуючи блокtryабоcatch, буде перервана або вбита, блокfinallyне буде виконаний, навіть не дивлячись на те, що програма продовжує працювати. -
Чому існує два класи
Date, один вjava.util packageінший вjava.sql?java.util.Dateпредставляє дату та час, аjava.sql.Dateпредставляє лише дату. Доповненнямjava.sql.Dateє класjava.sql.Time, який представляє тільки час.Клас
java.sql.Dateє субкласом (розширенням) класуjava.util.Date. Отже, що змінилося вjava.sql.Date:toString()формує інше уявлення рядка: yyyy-mm-dd- статичний метод
valueOf(String)створює дату з рядка з вказаним вище поданням - виключені гетери та сеттери для годин, хвабон та секунд
Клас
java.sql.Dateвикористовується в JDBC і призначений, щоб не мати складову часу, тобто години, хвабони, секунди та мілісекунди повинні бути нульовими… але це не є обов'язковим для класу. -
Поясніть маркери.
Шаблон інтерфейсу-маркера – це шаблон проектування в комп'ютерних науках, який використовується мовами програмування, які надають інформацію про об'єкти під час виконання . Це надає спосіб асоціації метаданих класу, де мова не має явної підтримки таких метаданих . Java для цього використовуються інтерфейси без вказівки методів.
Хорошим прикладом застосування інтерфейсу-маркера Java є інтерфейс
Serializable. Клас реалізує цей інтерфейс для вказівки, що йогоtransientдані можуть бути записані в потік байтів або на файлову систему.Головною проблемою інтерфейсу-маркера є те, що інтерфейс визначає угоду для класів, що її реалізують, і ця угода успадковується всіма субкласами. Це означає, що ви не зможете "де-реалізувати" маркер. У наведеному прикладі, якщо ви створите субклас, який ви не хотіли б серіалізувати (можливо тому, що він перебуває в минущому (transient) стані), ви повинні вдатися до явного кидання
NotSerializableException. -
Чому метод
main()оголошено якpublic static void?Чому public? Метод
mainмає модифікатор доступуpublic, тому він може бути доступний скрізь і для будь-якого об'єкта, який захоче використовувати цей метод для запуску програми. Тут я не кажу, що JDK/JRE мають подібну нагоду, оскільки java.exe або javaw.exe (для windows) використовують Java Native Interface (JNI) виклик для запуску методу, тому вони можуть викликати його в будь-якому випадку, незалежно від модифікатора доступу .Чому це? Давайте припустимо, що ми метод
mainне статичний. Тепер для виклику будь-якого методу вам необхідний екземпляр класу. Правильно? Java дозволяє мати перевантажені конструктори, це ми всі знаємо. Тоді який із них має бути використаний, і звідки візьмуться параметри для перевантаженого конструктора?Чому void? Немає застосування для значення, що повертається у віртуальній машині, яка фактично викликає цей метод. Єдине, що програма захоче повідомити процесу, що викликав, - це нормальне або ненормальне завершення. Це вже можливо використовуючи
System.exit(int). Чи не нульове значення має на увазі ненормальне завершення, інакше все в порядку. -
У чому різниця між створенням рядка як
new()і літералом (за допомогою подвійних лапок)?Коли ми створюємо рядок, використовуючи
new(), вона створюється в хіпі і також додається в пул рядків, у той же час рядок, створений за допомогою літералу, створюється тільки в пулі рядків.Вам необхідно ознайомитися з поняттям пула рядків глибше, щоб відповісти на це або подібні запитання. Моя порада - як слід вивчіть клас String і пул рядків .
-
Як працює метод
substring()класуString?Як і в інших мовах програмування, рядки Java є послідовністю символів. Цей клас більше схожий на службовий клас для роботи з цією послідовністю. Послідовність символів забезпечується наступною змінною:
/** The value is used for character storage. */ /** Значение используется для хранения символов */ private final char value[]; Для доступа к этому массиву в различных сценариях используются следующие переменные/** The offset is the first index of the storage that is used. */ /** Смещение – это первый индекс используемого хранабоща. */ private final int offset; /** The count is the number of characters in the String. */ /** Счет – это количество символов в строке. */ private final int count;Щоразу, коли ми створюємо підрядок від існуючого екземпляра рядка, метод
substring()лише встановлює нові значення зміннихoffsetтаcount. Внутрішній масив символів не змінюється. Це можливе джерело витоку пам'яті, якщо методsubstring()використовувати необережно:Початкове значення
value[]не змінюється. Тому якщо ви створите рядок довжиною 10000 символів і створите 100 підрядків з 5-10 символами в кожному, всі 101 об'єкти будуть містити один і той же символьний масив довжиною 10000 символів. Це без сумніву марнотратство пам'яті.Цього можна уникнути, змінивши код таким чином:
замінити
original.substring(beginIndex)наnew String(original.substring(beginIndex)), деoriginal– вихідний рядок.Примітка перекладача: я не можу сказати до якої версії Java це застосовно, але на даний момент у Java 7 цей пункт статті не актуальний. Метод substring()викликає конструктор класуnew String(value, beginIndex, subLen), що у свою чергу звертається до методуArrays.copyOfRange(value, offset, offset+count). Це означає, що у нас буде щоразу нове значення змінноїvalue[], що містить наше нове кількість символів. -
Поясніть роботу
HashMap. Як вирішено проблему дублікатів?Більшість з вас, напевно, погодиться, що
HashMapнайбільш улюблена тема для дискусій на інтерв'ю в даний час. Якщо хтось попросить мене розповісти «Як працюєHashMap?», я просто відповім: «За принципом хешування». Так просто, як це є.Отже, хешування по суті є способом призначити унікальний код будь-якої змінної/об'єкта після застосування будь-якої формули/алгоритму до своїх властивостей.
Визначення картки (
Map) таке: «Об'єкт, який прив'язує ключі до значень». Дуже просто, правда? Отже,HashMapмістить власний внутрішній класEntry, який має вигляд:static class Entry implements Map.Entry { final K key; V value; Entry next; final int hash; …//More code goes here }Коли хтось намагається помістити пару ключ-значення в
HashMap, відбувається таке:- Насамперед об'єкт ключа перевіряється на
null. Якщо ключnull, значення зберігається у позиціюtable[0]. Тому що хешкодnullзавжди 0. - Потім, наступним кроком обчислюється хеш значення викликаючи у змінної ключа свій метод
hashCode(). Цей хеш використовується для обчислення індексу в масиві для зберігання об'єктаEntry. Розробники JDK чудово розуміли, що методhashCode()може бути погано написаний і може повертати дуже велике чи дуже маленьке значення. Для вирішення цієї проблеми вони ввели іншийhash()метод і передають хешкод об'єкту цьому методу для приведення цього значення до діапазону розміру індексу масиву. - Тепер викликається метод
indexFor(hash, table.length)для обчислення точної позиції для зберігання об'єктаEntry. - Наразі головна частина. Як ми знаємо, два неоднакові об'єкти можуть мати однакове значення хешкода, як два різні об'єкти зберігатимуться в однаковому розташуванні в архіві [називається кошиком]?
Відповідь –
LinkedList. Якщо пам'ятаєте, класEntryмає властивість “next”. Ця властивість завжди вказує на наступний об'єкт у ланцюзі. Така поведінка дуже схожа наLinkedList.Отже, у разі збігів хешкод, об'єкти Entry зберігаються у формі
LinkedList. Коли об'єктEntryнеобхідно розмістити на конкретному індексі,HashMapперевіряє, чи існує на цьому місці інший об'єктEntry? Якщо там немає запису, наш об'єкт збережеться у цьому місці.Якщо в нашому індексі вже знаходиться інший об'єкт, перевіряється його поле
next. Якщо воно рівнеnull, наш об'єкт стає наступним вузлом вLinkedList. Якщо next не дорівнюєnull, ця процедура повторюється, доки знайдено полеnextрівнеnull.Що буде, якщо ми додамо інше значення ключа, що дорівнює доданому раніше? Логічно, що вона має замінити старе значення. Як це відбувається? Після визначення індексу позиції для об'єкта
Entry, пробігаючи поLinkedListрозташованому на нашому індексі,HashMapвикликає методequals()для значення ключа для кожного об'єктаEntry. Всі ці об'єктиEntryмаютьLinkedListоднакове значення хешкода, але методequals()перевірятиме на справжню рівність. Якщо ключ.equals(k)буде true , тоді обидва сприйматимуться як однаковий об'єкт. Це викликає заміну лише об'єкта-значення всередині об'єктаEntry.У такий спосіб
HashMapзабезпечує унікальність ключів. - Насамперед об'єкт ключа перевіряється на
-
Відмінності між інтерфейсами та абстрактними класами?
Це дуже поширене питання, якщо ви проходите співбесіду з програмістом рівня junior. Найбільш значущі відмінності наведені нижче:
- В інтерфейсах Java змінні апріорі
final. Абстрактні класи можуть містити неfinalзмінні. - Інтерфейс Java беззастережно не може мати реалізації. Абстрактний клас може мати екземпляри методів, що реалізують базову поведінку.
- Складові інтерфейсу повинні бути
public. Анотація клас може мати модифікатори доступу на будь-який смак. - Інтерфейс має бути реалізований ключовим словом
implements. Абстрактний клас має бути розширений за допомогою ключового слова extends . - Java клас може реалізовувати безліч інтерфейсів, але може успадковуватися тільки від одного абстрактного класу.
- Інтерфейс повністю абстрактний і не може мати екземплярів. Абстрактний клас також може мати примірників класу, але може бути викликаний, якщо існує метод
main(). - Абстрактний клас трохи швидше за інтерфейс, тому що інтерфейс передбачає пошук перед викликом будь-якого перевизначеного методу в Java. У більшості випадків це незначна відмінність, але якщо ви пишите критичний час додаток, вам необхідно врахувати і цей факт.
- В інтерфейсах Java змінні апріорі
-
Коли ви перевизначаєте методи
hashCode()таequals()?Методи
hashCode()іequals()визначені у класуObject, який є батьківським класом для всіх об'єктів Java. З цієї причини всі об'єкти Java успадковують базову реалізацію цих методів.Метод
hashCode()використовується для отримання унікального значення integer для цього об'єкта. Це значення використовується визначення розташування кошика, коли об'єкт необхідно зберігати у структурі даних на кшталтHashTable. За замовчуванням методhashCode()повертає ціле чисельне подання адресаи пам'яті, де зберігається об'єкт.Метод
equals(), як передбачає назву, використовується для простої еквівалентності об'єктів. Базова реалізація методу полягає у перевірці посилань двох об'єктів для перевірки їхньої еквівалентності.Зверніть увагу, що зазвичай необхідно перевизначати метод
hashCode()щоразу, коли перевизначено методequals(). Це необхідно для підтримки загальної угоди методуhashCode, в якому говориться, що рівні об'єкти повинні мати рівні хешкоди.Метод equals() повинен визначати рівність відносин (він має бути зворотним, симетричним та транзитивним). На додаток, він повинен бути стійким (якщо об'єкт не змінювався, метод повинен повертати те саме значення). Крім того,
o.equals(null)завжди має повертати false .hashCode()повинен бути також стійким (якщо об'єкт не змінювався за умовами методуequals(), він повинен продовжувати повертати те саме значення.Відношення між двома методами таке: завжди, якщо
a.equals(b), тодіa.hashCode()має бути таким самим, як іb.hashCode().
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ