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

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

Статья из группы Random
И снова всем привет! Продолжаем искать ответы на 250+ вопросов для Junior, Middle и Senior разработчиков. Вопросы довольно интересные, и мне самому нравится их разбирать: в такие моменты можно обнаружить пробелы в теоретических знаниях, причем в самых неожиданных местах.Разбор вопросов и ответов на собеседовании. Часть 2 - 1С предыдущей частью можно ознакомиться в этой статье. Но прежде чем мы начнём, я хочу напомнить, что:
  1. Вопросы, которые пересекаются с этой серией статей, я буду пропускать, чтобы лишний раз не дублировать информацию. Рекомендую прочитать эти материалы, так как там представлены самые частые (популярные) вопросы для собеседований по Java Core.
  2. Вопросы на DOU представлены на украинском, но у меня тут будет все на русском.
  3. Ответы можно было и расписать подробнее, но я не буду, так как тогда ответ на каждый вопрос может затянуть на целую статью. Да и так подробно вас ни на одном собесе не спросят.
По надобности буду оставлять ссылки, для более глубокого изучения. Полетели!

11. Назовите все методы класса Object

У класса Object есть 11 методов:
  • Class<?> getClass() — получение класса текущего объекта;
  • int hashCode() — получение хеш кода текущего объекта;
  • boolean equals​(Object obj) — сравнение текущего объекта с другим;
  • Object clone() — создание и возвращение копии текущего объекта;
  • String toString() — получение строкового представления объекта;
  • void notify() — пробуждение одного потока, ожидающего на мониторе данного объекта (выбор потока рандомный);
  • void notifyAll() — пробуждение всех потоков, ожидающего на мониторе данного объекта;
  • void wait() — переключает текущий поток в режим ожидания (замораживает его) на текущий монитор, работает только в synchronized блоке, пока какой-нибудь notify или notifyAll не разбудит поток;
  • void wait(long timeout) — также замораживает текущий поток на текущий монитор (на текущий synchronized), но уже с таймером выхода из этого состояния (ну или опять же: пока notify или notifyAll не разбудит);
  • void wait(long timeout, int nanos) — метод, аналогичный вышеописанному, но с более точным таймеров выхода из заморозки;
  • void finalize() — перед удалением этого объекта сборщиком мусора вызывается этот метод (напоследок). Он используется для очистки занимаемых ресурсов.
Для корректного использования методов hashCode, equals​, clone, toString, finalize их необходимо переопределять, учитывая текущую задачу и обстоятельства.

12. В чем различие между try-with-resources и try-catch-finally при работе с ресурсами?

Как правило при использовании try-catch-finally блок final применяли для закрытия ресурсов. В Java 7 появился новый вид оператора try-with-resources, аналог try-catch-finally для освобождения ресурсов, но более компактный и удобочитаемый. Давайте вспомним, как выглядит try-catch-finally:

String text = "some text......";
BufferedWriter bufferedWriter = null;
try {
   bufferedWriter = new BufferedWriter(new FileWriter("someFileName"));
   bufferedWriter.write(text); 
} catch (IOException e) {
   e.printStackTrace();
} finally {
   try {
       bufferedWriter.close();
   } catch (IOException e) {
       e.printStackTrace();
   }
}
А теперь давайте перепишем этот код, но с использованием try-with-resources:

String text = "some text......";
try(BufferedWriter bufferedWriter =new BufferedWriter(new FileWriter("someFileName"))) {
   bufferedWriter.write(text);
} catch (IOException e) {
   e.printStackTrace();
}
Как-то проще стало, не находите? Помимо упрощения, ещё есть пара моментов:
  1. В try-with-resources ресурсы, объявленные в скобках (которые будут закрыты), должны имплементировать AutoCloseable интерфейс и его единственный метод — close().

    Метод close выполняется в неявном finally блоке, иначе как программа поймет, как именно данный закрывать ресурс?

    Но, скорее всего, вы редко будете писать свои имплементации ресурсов и их метод закрытия.

  2. Последовательность выполнения блоков:

    1. Блок try.
    2. Неявный finally.
    3. Блок catch, который ловит исключения в предыдущих шагах.
    4. Явный finally.

    Как правило исключения, которые выпали ниже по списку, перебивают те, что выпали выше.

Представьте ситуацию, что при использовании try-catch-finally у вас в try падает исключение. Соответственно, сразу начинает исполняться определенный блок catch, в котором вы прописываете другое исключение (например, с сообщением, которое более подробно описывает ошибку), и вы хотите, чтобы метод прокидывал это исключение дальше. Следом идет выполнение блока finally, и в нём тоже падает исключение. Но уже другое. Какое же из этих двух исключений в итоге выбросит данный метод? Исключение, которое выбросил блок finally! Но и тут есть один момент с try-with-resources. Теперь рассмотрим поведение try-with-resources в этой же ситуации. У нас падает исключение в блоке try при попытке закрытия ресурсов в методе close(), то есть в неявном finally. Какое же из этих исключений отловит catch? То, которое выбросил блок try! Исключение из неявного finally (из метода close()) будет игнорироваться. Это игнорирование еще называют подавлением исключений.

13. Что такое побитовые операции?

Побитовые операции — это операции над цепочками битов, которые включают в себя логические операции и побитовые сдвиги. Логические операции:
  • побитовое И — сравнивает битовые значения, и по ходу этого любой бит, установленный в 0 (false), устанавливает соответствующий бит в результате как 0. То есть, если в обоих сравниваемых значениях бит был 1 (true), в результирующем тоже будет 1.

    Обозначается как — AND, &

    Пример: 10111101 & 01100111 = 00100101

  • побитовое ИЛИ — операция, обратная предыдущей. Любой бит, установленный в 1, устанавливает аналогичный бит в результате как 1. И соответственно, если в обоих сравниваемых значениях бит был 0, в результирующем тоже будет 0.

    Обозначается как — OR, |

    Пример: 10100101 | 01100011 = 11100111

  • побитовое НЕ — применяется к одному значению, переворачивает (инвертирует) биты. То есть, те биты что были 1, станут 0; а те что были 0, станут 1.

    Обозначается как — NOT, ~

    Пример: ~10100101 = 01011010

  • побитовое исключающее ИЛИ — сравнивает битовые значения, и если в обоих значениях бит равен 1, то результат будет 0, также если в обоих значениях бит 0, результат будет 0. То есть, чтобы результат был равен 1, нужно, чтобы только один из битов был равен 1, а второй равен 0.

    Обозначается как — XOR, ^

    Пример: 10100101 ^ 01100011 = 11000110

Побитовые сдвиги>> или << сдвигают биты значения в указанную сторону, на указанное число. Освободившиеся позиции заполняются нулями. Например:
  1. 01100011 >> 4 = 00000110
  2. 01100011 << 3 = 00011000
Также есть исключение при сдвиге вправо отрицательного числа. Как вы помните, первый бит отвечает за знак, и если этот бит равен 1, то число отрицательное. Если вы будете двигать отрицательное число, освободившиеся позиции будут заполняться уже не нулями, а единицами, так как необходимо поддерживать знаковый бит. Например: 10100010 >> 2 = 11101000 При этом в Java существует дополнительный оператор беззнакового сдвига вправо >>> Данный оператор — аналог >>, при сдвиге которым освободившиеся позиции заполняются 0, независимо от того, отрицательное число или положительное. Например: 10100010 >>> 2 = 00101000 Подробнее о побитовых операциях читаем вот тут.Разбор вопросов и ответов на собеседовании. Часть 2 - 2В качестве примеров использования побитовых сдвигов в Java, вы можете привести метод hash() у HashMap-ы, который используется для определения специального внутреннего хеш кода ключа:Разбор вопросов и ответов на собеседовании. Часть 2 - 3Этом метод позволяет равномерно распределять данные в HashMap, чтобы минимизировать количество коллизий.

14. Объекты каких стандартных классов immutable есть в Java?

Immutable — это объект, который не позволяет изменять свои первоначальные параметры. Возможно, он имеет методы, которые возвращают новые объекты данного типа, с параметрами, которые вы хотели изменить. Некоторые стандартные immutable объекты:
  • безусловно, самый известный immutable объект в Java — это String;
  • экземпляры классов-оберток, которые оборачивают стандартные типы: Boolean, Character, Byte, Short, Integer, Long, Double, Float;
  • объекты, которые как правило используются для особо БОЛЬШИХ чисел — BigInteger и BigDecimal;
  • объект, который является единицей в стектрейсах (например, в стектрейсе исключений) StackTraceElement;
  • объект класса File — может изменять файлы, но при этом сам по себе он неизменен;
  • UUID — который часто используется как уникальный id элементов;
  • все объекты классов пакета java.time;
  • Locale — используется для определения географического, политического или культурного региона.

15. Каковы преимущества immutable object перед обычными объектами?

  1. Такие объекты — безопасные при использовании в многопоточной среде. Используя их, вы можете не беспокоиться о том, что будут утеряны данные из-за состояния гонки потоков. В отличие от работы с обычными объектами: в таком случае вам придется очень хорошо продумать и проработать механизмы использования объекта в параллельной среде.
  2. Immutable объекты являются хорошими ключами в map, ведь если использовать изменяемый объект, а затем объект изменит свое состояние, при использовании HashMap может возникнуть путаница: объект все еще будет присутствовать, и если использовать containsKey(), то его можно и не найти.
  3. Immutable объекты отлично подходят для хранения неизменных (константных) данных, которые ни в коем случае не должны быть изменены во время работы программы.
  4. “Атомарность по отношению к сбою” — если immutable объект выбросит исключение, то он всё равно не останется в нежелательном (сломанном) состоянии.
  5. Данные классы просты в тестировании.
  6. Не нужны такие дополнительные механизмы как конструктор копирования и реализация клона.

Вопросы по ООП

Разбор вопросов и ответов на собеседовании. Часть 2 - 4

16. В чём преимущества ООП в целом и по сравнению с процедурным программированием?

Итак, преимущества ООП:
  1. Сложные приложения писать проще, чем процедурным программированием, так как у нас все разбито на маленькие модули — объекты, которые взаимодействуют между собой — и в итоге программирование сводится ко взаимоотношениями между объектами.
  2. Приложения, написанные с помощью ООП, гораздо более простые в модификации (при соблюдении концепций проектирования).
  3. Так как данные и операции над ними образуют единую сущность, они не размазываются по всему приложению (что нередко бывает при процедурном программировании).
  4. Инкапсуляция информации защищает наиболее критичные данные для работы от пользователя.
  5. Возможно переиспользование одного и того же кода, с разными данными, ведь классы позволяют создавать множество объектов, у каждого из которых есть собственные значения атрибутов.
  6. Наследование и полиморфизм также позволяют переиспользовать и расширять уже существующий код (вместо дублирования похожего функционала).
  7. Более простая расширяемость приложения, нежели при процедурном подходе.
  8. Подход ООП дает возможность абстрагироваться от деталей реализации.

17. Расскажите, какие недостатки есть в ООП

К сожалению, и они присутствуют:
  1. ООП требует большой объём теоретических знаний, который нужно освоить, прежде чем вы сможете что-либо написать.Разбор вопросов и ответов на собеседовании. Часть 2 - 5
  2. Идеи ООП не так просты для понимания и применения на практике (нужно быть в душе немного философом).
  3. При применении ООП немного снижается производительность функционирования ПО из-за более сложной организации системы.
  4. Для ООП подхода требуется больше памяти, так как всё состоит из классов, интерфейсов, методов, которые занимают гораздо больше памяти, нежели обычные переменные.
  5. Временные затраты на первоначальный анализ больше, чем при процедурном.

18. Что такое статический и динамический полиморфизм

Полиморфизм дает возможность объектам вести себя по-разному для одного и того же класса или интерфейса. Существует два вида полиморфизма, которые еще известны как ранее и позднее связывание. Статический полиморфизм, или ранее связывание:
  • происходит во время компиляции (на ранней стадии жизненного цикла программы);
  • решает, какой метод выполнять во время компиляции;
  • перегрузка метода — это пример статического полиморфизма;
  • к раннему связыванию относятся приватные, статические и терминальные методы;
  • наследование не участвует в раннем связывании;
  • в статическом полиморфизме участвуют не конкретные объекты, а информация о классе, тип которого представлен слева от имени переменной.
Динамический полиморфизм, или позднее связывание:
  • происходит во время выполнения (во время работы программы);
  • динамический полиморфизм решает, какая конкретно реализация будет у метода во время выполнения;
  • переопределение метода — пример динамического полиморфизма;
  • позднее связывание — это назначение конкретного объекта, ссылки его типа или его суперкласса;
  • наследование связано с динамическим полиморфизмом.
Подробнее о различиях раннего и позднего связывания можно прочесть вот в этой статье.

19. Дайте определение принципа абстракции в ООП

Абстракция в ООП — это способ выделить набор значимых характеристик объекта, исключив незначимые детали. То есть при проектировании программы с ООП подходом вы сосредотачиваетесь на моделях в общем, без углубления в детали их реализации. В Java за абстракцию отвечают интерфейсы. Например, у вас есть машина, и это будет интерфейс. А различные взаимодействия с ней — например, завести двигатель, использовать коробку передач — это функции, которые мы используем без углубления в детали реализации. Ведь в тот момент, когда вы ведете машину, вы не думаете, как конкретно коробка передач исполняет своё предназначение, или как ключ заводит двигатель, или каким именно образом руль поворачивает колеса. И если даже реализацию одной из этой функциональности заменить (например, двигатель), вы этого можете и не заметить. Вам это не важно: вы не углубляетесь в детали реализации. Вам важно чтобы действие выполнялось. Собственно, это и есть абстрагирование от деталей реализации. На этом моменте мы сегодня и остановимся: продолжение следует!Разбор вопросов и ответов на собеседовании. Часть 2 - 6
Другие материалы серии:
Комментарии (11)
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
Юрий Уровень 31
12 марта 2021
Ждем продолжения! Спасибо тебе!!!
Милана Уровень 1
11 марта 2021
В 12 вопросе нужно добавить ещё Closeable интерфейс https://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html
Антон Уровень 25
11 марта 2021
Спасибо за статью! Жду продолжения!
Артем Шлей Уровень 2
11 марта 2021
насчет + и - ООП все спорно
Ainur Уровень 28
11 марта 2021
Спасибо!!!
Илья Уровень 30
11 марта 2021
Ценный материал! Спасибо)
BotGabe Уровень 6 Expert
10 марта 2021
Полезные статьи, пишите еще👍