Привет! На JavaRush собрались разные люди. Одни из нас только хотят стать Java-разработчиками, вкладывая много времени и сил в развитие, а другие — уже Java developer-ы. В том или ином случае, необходимо быть готовыми к испытаниям — техническим собеседованиям. Это испытание не из легких, и помимо моральной подготовки нужна и техническая. Разбор вопросов и ответов на собеседовании. Часть 1 - 1Недавно я наткнулся на большой список вопросов для собеседований на Java разработчика на dou. Данные вопросы поделены на различные уровни — Junior, Middle и Senior. Не пугайтесь: не все вопросы из легких, но те, что “со звездочкой” довольно редко задают. Вопросы — это хорошо, но мне бы хотелось попытаться ответить на большинство из них. Понятное дело, что я не вложусь в рамки одной статьи, как-никак, вопросов там чрезвычайно много. Поэтому это будет целый цикл из статьей-ответов на такие вопросы. Сразу подчеркну несколько моментов:
  1. Есть отличная статья с топом вопросов и ответов для них. Некоторые вопросы пересекаются с представленным выше списком (250+), поэтому эти вопросы будут пропускаться, дабы не дублировать лишний раз информацию.

  2. Вопросы представлены на украинском, но так как большинство участников JavaRush русскоязычные (да и я в большей мере тоже), ответы будут на русском.

  3. Ответы будут краткими, так как если расписывать очень подробно, ответы на некоторые вопросы могут потянуть на отдельную статью. Да и на собеседованиях настолько подробные и объемные ответы не нужны, ведь у вас вашего интервьюера есть всего лишь час на то, чтобы опросить вас по необходимым темам (а, как вы помните, тем хватет). Для любителей покопать поглубже я буду оставлять ссылки.

Итак, начнём.

Вопросы и ответы уровня Junior

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

Общие вопросы

1. Какие вы знаете шаблоны проектирования? Расскажите о двух шаблонах, которые использовали в работе.

Шаблонов есть огромное множество: начать знакомство с ними можно с этой и этой статьи. Ну а для тех из вас, кто хочет обстоятельно ознакомиться с ними, рекомендую прочитать книгу “Head First. Паттерны проектирования”. С ее помощью вы сможете подробно и в легкой форме изучить самые базовые паттерны проектирования. Говоря о шаблонах проектирования, которые вы можете привести в качестве примеров на собеседовании, на ум приходят:
  • Builder — часто используемый шаблон, альтернатива классическому созданию объектов;
  • паттерн Стратегия, который по своей сути представляет полиморфизм. То есть, у нас есть один интерфейс, но поведение программы будет меняться в зависимости от того, какую конкретно реализацию этого интерфейса передали в функционал (сейчас стратегия фактически везде используется в java-приложениях).
Если этого вам мало, обратите внимание на Spring (если вы с ним уже знакомы), ведь он представляет собой целую платформу фреймворков, которые в свою очередь пронизаны паттернами вдоль и поперек. Вот вам пара примеров того, о чем я говорю:
  • Factory — в ApplicationContext (ну или в BeanFactory);
  • Singleton — все бины по умолчанию синглтоны;
  • Proxy — по сути все в спринге так или иначе использует этот паттерн, например, АОП;
  • Chain of responsibility — паттерн, по концепции которого работает Spring Security;
  • Template — используется в Spring Jdbc.

Java Core

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

2. Какие типы данных есть в Java?

В Java есть примитивные типы данных:
  • byte — целые числа в пределах -128 до 127, весит 1 байт;
  • short — целые числа в пределах -32768 до 32767, весит 2 байта;
  • int — целые числа -2147483648 до 2147483647, весит 4 байта;
  • long — целые числа в пределах 9223372036854775808 до 9223372036854775807, весит 8 байтов;
  • float — числа с плавающей запятой в пределах -3.4E+38 до 3.4E+38, весит 4 байта;
  • double — числа с плавающей запятой в пределах -1.7E+308 до 1.7E+308, весит 8 байтов;
  • char — одиночные символы в UTF-16, весит 2 байта;
  • boolean значения true/false, весит 1 байт.
И ссылочные типы данных, которые указывают на объекты в куче.

3. Чем объект отличается от примитивных типов данных?

Первое отличие: количество занимаемой памяти: примитивы занимают очень мало, ведь они содержат лишь собственное значение, в то время как объекты могут содержать очень и очень много различных значений: как примитивов, так и ссылок на другие объекты. Второе отличие: Java —это объектно-ориентированный язык, поэтому в ней все работает через взаимодействие между объектами, и примитивы тут не сильно вписываются (собственно, поэтому Java — это не 100% объектно-ориентированный язык). Третье, вытекающее со второго: так как Java ориентирована на взаимодействие между объектами, у этих объектов есть много различных механизмов для управления. Например, конструкторы, методы, исключения (которые работают в первую очередь с объектами), и т.д. Собственно, чтобы примитивы могли как-то ввязаться (работать) в этой объектно ориентированной среде и были придуманы обертки (wrappers) для примитивных типов (Integer, Character, Double, Boolean...)

4. Чем отличаются передача параметров по ссылке и по значению?

Примитивные поля хранят свое значение: например, если мы задали int i = 9; поле i хранит значение 9. Когда у нас есть ссылка на объект, это значит, что мы имеем поле со ссылкой на объект, или другими словами — со значением адреса объекта в памяти.

Cat cat = new Cat();
Получается, поля со ссылкой на объект тоже хранят значения, значения адреса памяти. То есть, cat хранит значение адреса объекта new Cat() в памяти. Когда мы передаем параметр в некоторый метод, то происходит копирование его значения. В случае с примитивом будет копироваться значение примитива. Соответственно, в методе будет вестись работа с копией, при изменении которой оригинал не затронется. В случае со ссылочным типом будет копироваться значение адреса памяти, соответственно, адрес будет все тем же, как и объект, на который он указывает. И если мы будем менять объект по этой новой ссылке, он будет изменен и для старой (ведь они обе указывают на один и тот же объект).

5. Что такое JVM, JDK, JRE?

JVM — Java Virtual Machine — это виртуальная машина, которая запускает Java байткод, предварительно созданный компилятором. JRE — Java Runtime Environment — по сути, это среда для запуска java-приложений, которая содержит JVM, стандартные библиотеки и другие компоненты для запуска апплетов и приложений, написанных на языке программирования Java. Другими словами JRE — пакет всего необходимого для запуска скомпилированной Java-программы, но при этом не содержащий инструментов и утилит, таких как компиляторы или отладчики для разработки приложений. JDK — Java Development Kit — расширенный набор JRE, то есть, среда не только для запуска, но и для разработки java-приложений. JDK содержит все, что есть в JRE, плюс различные дополнительные инструменты — компиляторы и отладчики, которые нужны для создания приложений на Java (также содержит java-доки).Разбор вопросов и ответов на собеседовании. Часть 1 - 4

6. Зачем используют JVM?

Как говорилось выше, Java Virtual Machine — это виртуальная машина, которая запускает Java байткод, предварительно созданный компилятором. То есть, JVM не понимает исходный код Java. Поэтому сперва происходит компиляция .java файлов, которые после компиляции имеют расширение уже .class и которые и которые представлены в виде того самого байт кода, который понимает JVM. JVM для каждой OC своя, поэтому получив файлы в байт коде, JVM исполняет его, адаптируя под ОС, на которой это происходит. Собственно, из-за разных JVM версии JDK (или JRE) отличаются для разных ОС (под каждую из них нужна своя JVM). Давайте вспомним, как происходит разработка на других языках программирования. Вы разрабатываете программу, затем её код компилируется в машинный код для конкретной ОС, и после вы можете его запускать. Другими словами, под каждую систему вам нужно писать разные версии программы. В то время как на Java, благодаря двойной обработке кода (компиляция и обработка байт кода JVM), вы можете пользоваться преимуществами кроссплатформенности. Мы создали однажды код, перекомпилировали его в байткод, перенесли его на любую ОС, и уже местная JVM и запускает код. Это и есть легендарное свойство Java — пишешь однажды, запускаешь где угодно.Разбор вопросов и ответов на собеседовании. Часть 1 - 5Подробнее об этом — в статье “Компиляция и исполнение Java-приложений под капотом”.

7. Что такое bytecode?

Как я и говорил выше, компилятор преобразовывает Java-код в промежуточный — bytecode (файлы с расширением .java в файлы с расширением .class). Байткод во многом похож на машинный код, только он использует набор инструкций не реального процессора, а виртуального. При этом он может включать в себя участки, ориентированные на использование JIT-компилятора, оптимизирующего выполнение команд под реальный процессор, на котором запущена программа. JIT-компиляция, называемая ещё компиляцией на лету— это технология, которая увеличивает производительность программы, использующей байткод, через компиляции байткода в машинный или в другой формат во время работы программы. Как вы могли догадаться, JVM и использует JIT-компилятор, когда запускает байткод. Давайте взглянем на пример bytecode:Разбор вопросов и ответов на собеседовании. Часть 1 - 6Не слишком читаемо, не так ли? Ну так, это и не для нас инструкция, а для JVM. Вот статья, которая поможет получше разобраться в этом вопросе.

8. Каковы признаки JavaBean?

JavaBeans — Java-класс с соблюдением определенных правил. Вот несколько правил для написания JavaBean:
  1. Класс должен содержать пустой (без параметров) конструктор с открытым доступом с модификатором доступа public. Этот конструктор дает возможность создавать объект данного класса без лишних проблем (чтобы не было лишней возни с параметрами).

  2. Доступ ко внутренним полям класса осуществляется через методы get и set, которые должны быть стандартными. Например, если поле name, то getName и setName и т. д. Это, в свою очередь, позволяет различным инструментам (фреймворкам) без осложнений автоматически определять и обновлять содержание bean-ов.

  3. Класс должен содержать переопределенные версии методов equals()hashCode() и toString().

  4. Класс должен быть сериализуемым, то есть должен иметь интерфейс маркер — Serializable или имплементировать интерфейс Externalizable. Это нужно для того, чтобы состояние объекта bean можно надежно сохранять, хранить и восстанавливать.

Разбор вопросов и ответов на собеседовании. Часть 1 - 7Про виды JavaBeans можно почитать в этом материале.

9. Что такое OutOfMemoryError?

OutOfMemoryError — одна из критических ошибок во время исполнения программы, связанная с работой виртуальной машины Java (JVM). Вызывается в тех случаях, когда JVM не может выделить объект, потому что на него не хватает памяти, и сборщик мусора не может выделить больше памяти. Некоторые виды OutOfMemoryError:
  • OutOfMemoryError: Java heap space — объект не может быть размещен в куче Java из-за недостатка памяти. Ошибку может вызвать утечка памяти или то, что размер кучи по умолчанию недостаточен для текущего приложения.

  • OutOfMemoryError: GC Overhead limit exceeded — из-за того, что объем данных едва помещается в кучу, сборщик мусора работает все время, а программа Java работает очень медленно, и как итог — превышается предел накладных расходов сборщика мусора и приложение падает с данной ошибкой.

  • OutOfMemoryError: Requested array size exceeds VM limit — указывает на то, что приложение попыталось выделить память для массива, размер которого превышает размер кучи, что, опять же может быть из-за недостаточного количества выделенной памяти по умолчанию.

  • OutOfMemoryError: Metaspace — в куче закончилось место, выделенное для метаданных (метаданные — это инструкции классов, методов).

  • OutOfMemoryError: request size bytes for reason. Out of swap space — произошел некоторый сбой при попытке выделения памяти из кучи и как итог — нехватка памяти в куче.

10. Что такое стек трейс? Как его получить?

Стек трейс (Stack Trace) — это список классов и методов, которые были вызваны до этого момента приложения. Вызвать стек трейс в определенной точке приложения можно так:

StackTraceElement[] stackTraceElements =Thread.currentThread().getStackTrace();
Таким образом мы получим массив стек трейс элементов, расположенных в порядке LIFO — Last In First Out.Разбор вопросов и ответов на собеседовании. Часть 1 - 8В Java, как правило, когда говорят о стек трейсе то имеется ввиду стек трейс, который выводится в консоли при возникновении ошибки (или исключения). Получить стек трейс исключений можно так:

StackTraceElement[] stackTraceElements;
try{
                ...
} catch (Exception e) {
   stackTraceElements = e.getStackTrace();
}
Ну и если мы говорим о выводе стек трейса исключения в консоли:

try{
                ...
} catch (Exception e) {
  e.printStackTrace();
}
Также, если у нас возникнет ошибка, unchecked исключение или checked, которое мы не обработаем, а только будем пробрасывать, то при падении приложения мы получим автоматически стек трейс исключений в консоли. Небольшой пример стектрейс исключения в консоли:Разбор вопросов и ответов на собеседовании. Часть 1 - 9Подробнее о Stack Trace можете почитать вот тут. На этом вопросе мы сегодня и остановимся...Разбор вопросов и ответов на собеседовании. Часть 1 - 10
Другие материалы серии: