JavaRush/Java блог/Архив info.javarush/История одного собеседования: интересные вопросы
GuitarFactor
30 уровень

История одного собеседования: интересные вопросы

Статья из группы Архив info.javarush
участников
Недавно мне довелось посетить собеседование на позицию стажёра в одной из крупных IT-компаний. История одного собеседования: интересные вопросы - 1Это было моё первое IT-собеседование и, на мой взгляд, оно выдалось интересным. В общей сложности меня “допрашивали” больше 3 часов (этому предшествовали ещё домашние задания и тест в офисе на компьютере). Хочу отдать должное собеседующему, который не ставил крест, когда я отвечал на вопрос неверно, а с помощью своих наводящих вопросов заставлял меня вдумываться и приходить к верному ответу. Ниже я представлю несколько “зарисовок” – на мой взгляд, достаточно интересных вопросов, некоторые из которых дали мне более глубокое понимание отдельных аспектов в Java. Возможно, кому-то эти вещи покажутся очевидными, но думаю, найдётся те, для кого это будет полезно. Ниже фразы выделены следующими шрифтами: Собеседующий — жирным шрифтом Закадровые пояснения и мои мысли — курсивом Мои ответы — обычным шрифтом С предысторией закончили, перейдём к делу)

Зарисовка 1. “Казалось бы простой метод”

Напишите, как бы вы реализовали метод, возвращающий результат деления числа а на число b Собеседующий пишет на листочке
int divide(int a, int b) {
}
*Я недоверчиво покосился на листок с сигнатурой метода. В чём подвох?* Пишу:
int divide(int a, int b) {
    return a/b;
}
А какие-нибудь проблемы могут быть с этим методом? *Ловлю дииииикий тупняк* Вроде нет.. Далее следует законный вопрос: А если b=0? *Воу, меня сейчас выгонят из этого кабинета, если продолжу в том же духе!* Ах да, разумеется. Здесь у нас аргументы типа int, поэтому будет выброшен Arithmetic Exception. В случае, если бы аргументы были типа float или double, получилась бы Infinity. А что с этим будем делать? Начинаю писать try/catch
int divide(int a, int b) {
    try {
        return a/b;
    } catch (Exception e) {
        e.printStackTrace();
        return ... // ??? what the hack?
    }
}
*Дохожу до return и подвисаю: что-то ведь надо вернуть в случае ошибки. Но как это “что-то” отличить от результата вычисления?* А что будем возвращать? Гм… Я бы поменял тип возвращаемой переменной на Integer и в случае эксэпшна возвращал бы null. Давайте представим, что не можем менять тип. Можем как-то выкрутиться? Может, можем ещё что-то сделать с эксэпшном? *Тут дошло* Можем ещё пробросить в вызывающий метод! Верно. Как он будет выглядеть?
int divide(int a, int b) throws ArithmeticException{
    return a/b;
}

void callDivide(int a, int b) {
    try {
        divide(a, b);
    } catch (ArithmeticException e) {
        e.printStackTrace();
    }
}
А обрабатывать исключение обязательно? Да, ведь мы явно пробрасываем его из метода divide. (*Тут я ошибся! Далее следуют наводящие вопросы собеседующего, чтобы прийти к верному ответу*) А Arithmetic Exception - это какое исключение – checked или unchecked? Это Runtime exception, значит unchecked. *Тут следует убийственный вопрос* То есть получается, с Ваших слов, если мы в сигнатуре метода указали throws Arithmetic Exception, то оно стало checked исключением? *Ух ё!* Наверное… нет. Да, не стало. Если мы указали в сигнатуре throws /unchecked exception/ мы всего лишь предупреждаем, что метод может выбрасывать исключение, но обрабатывать его в вызывающем методе не обязательно. С этим разобрались. А ещё что-то можем сделать, чтобы избежать ошибки? *После некоторых раздумий* Да, можем ещё проверять, if (b==0). И выполнять какую-то логику. Верно. Таким образом, мы можем пойти 3 путями:
  • try/catch
  • throws – проброс в вызывающий метод
  • проверка аргументов
В этом случае с divide какой из методов Вам кажется предпочтительнее?
Я бы выбрал проброс исключения в вызывающий метод, т.к. в методе divide не ясно, как этот эксэпшн обработать и какой результат типа int вернуть в случае ошибки. А в вызывающем методе использовал бы проверку аргумента b на равенство нулю. Вроде бы такой ответ удовлетворил собеседующего, но если честно, не уверен, что этот ответ однозначный))

Зарисовка 2. “Кто быстрей?”

После стандартного вопроса, чем ArrayList отличается от LinkedList, последовал такой: Что произойдёт быстрее — вставка элемента в середину ArrayList или в середину LinkedList? *Тут меня перемкнуло, я вспомнил, что везде читал что-то вроде “используйте LinkedList для вставки или удаления элементов в середину списка”. Дома даже перепроверил по лекциям JavaRush, там фраза: “если ты собираешься вставлять (или удалять) в середину коллекции много элементов, то тебе лучше использовать LinkedList. Во всех остальных случаях – ArrayList.” Ответил на автомате* Быстрее будет с LinkedList. Поясните, пожалуйста
  1. Для того чтобы вставить элемент в середину ArrayList, мы за константное время находим элемент в списке, а потом пересчитываем индексы элементов справа от вставляемого, за линейное время.
  2. Для LinkedList.. Мы сначала за линейное время доходим до середины и затем за константное время вставляем элемент, меняя для соседних элементов ссылки.
Так получается, что быстрее? Гм… Получается одинаково. А когда LinkedList всё же быстрее? Получается, что когда вставляем в первую половину списка. Например, если вставлять в самое начало, в ArrayList придётся пересчитать все индексы до самого хвоста, а в LinkedList всего лишь поменять ссылку у первого элемента. Мораль: не верьте дословно всему что написано, даже на JavaRush!)

Зарисовка 3. “Куда же без equals и hashcode!”

Разговор об equals и hashcode был очень долгий – как переопределяем, какая реализация в Object, что происходит под капотом, когда вставляется элемент в HashMap и т.д. Приведу только ряд интересных на мой взгляд моментов* Представьте, что мы создали класс
public class A {
    int id;

    public A(int id) {
        this.id = id;
    }
}
И не переопределили equals и hashcode. Опишите, что произойдёт при выполнении кода
A a1 = new A(1);
A a2 = new A(1);
Map<A, String> hash = new HashMap<>();
hash.put(a1, "1");
hash.get(a2);
*Хорошо что перед собеседованием специально уделил пару дней на понимание основных алгоритмов, их сложности и структур данных – очень помогло, спасибо CS50!*
  1. Создаём два экземпляра класса A

  2. Создаём пустую мапу, по умолчанию имеющую 16 корзин. В качестве ключа выступает объект класса A, в котором не переопределены методы equals и hashcode.

  3. Кладём a1 в мапу. Для этого сначала вычисляем хэш a1.

    Чему будет равен хэш?

    Адресу ячейки в памяти – это реализация метода из класса Object

  4. Исходя из хэша, вычисляем индекс корзины.

    А как мы можем его вычислить?

    *Тут к сожалению я не дал вразумительный ответ. У вас есть длинное число – хэш, и есть 16 корзин – как определить индекс, чтобы объекты с разным хэшем равномерно распределялись по корзинам? Я мог бы предположить, что индекс вычисляется так:

    int index = hash % buckets.length

    Уже дома посмотрел, что оригинальная реализация в исходниках несколько отличается:

    static int indexFor(int h, int length)
    {
        return h & (length - 1);
    }
  5. Проверяем, что не произошло коллизий и вставляем a1.

  6. Переходим к методу get. Экземпляры a1 и a2 гарантированно имеют разный hash (разный адрес в памяти), поэтому мы ничего не найдём по этому ключу

    А если переопределим только hashcode в классе A и попытаемся вставить в хэшмап сначала пару с ключом a1, а потом с a2?

    Тогда сначала найдём нужную корзину по hashcode – эта операция будет выполнена корректно. Далее начнём идти по объектам Entry в прикреплённом к корзине ЛинкедЛисту и сравнивать ключи по equals. Т.к. equals не переопределён, то берётся базовая реализация из класса Object – сравнение по ссылке. a1 и a2 гарантированно имеют разные ссылки, поэтому мы “промахнёмся” мимо вставленного элемента a1, и a2 будет помещён в ЛинкедЛист в качестве нового узла.

    Какой же вывод? Можно ли использовать в качестве ключа в HashMap объект с не переопределёнными equalshashcode?

    Нет, нельзя.

Зарисовка 4. “Давайте нарочно сломаем!”

После вопросов об Error и Exception последовал такой вопрос: Напишите простой пример, когда функция выкинет StackOverflow. *Тут я вспомнил, как меня кумарил этот эррор, когда я пытался написать какую-нибудь рекурсивную функцию* Наверное, это случится в случае рекурсивного вызова, если неверно указано условие выхода из рекурсии. *Дальше я стал что-то мудрить, в итоге собеседующий помог, всё оказалось просто*
void sof() {
    sof();
}
А чем этот эррор отличается от OutOfMemory? *Тут я не ответил, уже потом понял, что это был вопрос на знание Stack и Heap памяти Java (в Stack хранятся вызовы и ссылки на объекты, а в Heap памяти – сами объекты). Соответственно, StackOverflow выкидывается, когда больше нет места в Stack памяти для очередного вызова метода, а OutOfMemory – место под объекты закончилось в Heap памяти*
Вот такие моменты из собеседования мне запомнились. На стажировку в итоге меня взяли, так что впереди у меня 2,5 месяца обучения и, если всё сложится хорошо, работа в компании) Если будет интересно, могу написать ещё одну статейку, уже поменьше, с разбором простой, но показательной задачки, которую мне дали на собеседовании в другую компанию. На этом у меня всё, надеюсь, кому-то эта статья поможет углубить или расставить по полочкам свои знания. Всем приятного обучения!
Комментарии (42)
  • популярные
  • новые
  • старые
Для того, чтобы оставить комментарий Вы должны авторизоваться
Александр
Уровень 20
20 апреля 2020, 16:00
Когда начинал на JR проходить задания, случайно наткнулся на эту статью. Было понятно буквально НИЧЕГО. Спустя 9 месяцев занятий Java (не на JR, но в том числе) все пункты стали понятными и даже в каком то смысле легкими... Хотя придешь на собес, перенервничаешь и не ответишь что такое класс и метод :-D
Alexander
Уровень 2
15 января 2020, 23:00
Ок, отвечу сам, вдруг кому-то предстоит)) дается 30 вопросов и 30 минут, для успешного завершения нужно набрать больше половины. Много "задачек - фрагментов кода" на самые разные темы(много про наследование, переопределение методов и конструкторов, интерфейсы, коллекции и потоки). Тест на английском, но там больше кода, все с вариантами ответов. Из того что нашел более ли менее похожие вопросы здесь: https://proghub.ru/t/java-basic , особое внимание именно "вопросам - задачкам из кода".
Евгений
Уровень 20
19 января 2020, 21:39
Скажите, пожалуйста, а без разговорного английского имеет смысл пробовать? Как проходила проверка на знание английского?
Alexander
Уровень 2
24 января 2020, 14:12
Был небольшой диалог(минут на 5), из вопросов, типа: какие навыки из предыдущей работы могут пригодятся в новой? где и сколько учили английский? почему выбрали IT? что приходилось делать на прошлой работе? вообщем никаких спец. терминов и проф. ориентированных вопросов не было , все можно попробовать обяснить простыми словами, вопросы тоже задавали используя базовые слова. Как правило вопросы о предыдущей работе самые популярные.
Александр
Уровень 20
20 апреля 2020, 15:58
Привет, я вот хочу к ним в школу попасть, у них несколько этапов отбора: Рассмотрение резюме Выполнение технического задания (удалённо) Собеседование с техническим специалистом (удалённо) Проверка английского языка (удалённо) К какому этапу относится прохождение теста?
Alexander
Уровень 2
21 мая 2020, 14:20
Действительно, сейчас вроде тест убрали (во всяком в этапах отбора его нет).
Alexander
Уровень 2
10 января 2020, 01:32
Спасибо за статью, подскажите, какого вида вопросы были в тесте на компьютере в офисе?
aapopov812
Уровень 22
9 сентября 2018, 06:35
Как все прошло??? Взяли??
Archie369
Уровень 18
25 марта 2017, 19:33
Спасибо за статью, надеюсь у тебя все получится
Inspiron
Уровень 32
25 марта 2017, 13:24
честно говоря это собеседование на стажёра не отличается от собеседования на джуна, которые проходил я ))
Torin
Уровень 27
20 марта 2017, 17:06
Очень интересный отчет, автор. Плюс в карму, пиши еще!
Str3psils
Уровень 17
20 марта 2017, 10:17
Интересная статья вышла, у меня тестовые задания и вопросы были куда хуже.
GuitarFactor
Уровень 30
20 марта 2017, 10:31
Хуже, это в каком смысле? Сложнее или из серии «спрошу-ка я какую-нибудь ерунду, которая редко используется, но зато я о ней знаю»?
Str3psils
Уровень 17
20 марта 2017, 14:05
Тестовые задания сводились к работе с бд, а из вопросов — основы ООП. Остальное посчитали в то время не нужным, в итоге когда приступает человек к работе, он начинает менять цвет волос от объема информации, которую ему предстоит познать покинув стены университета.
GuitarFactor
Уровень 30
20 марта 2017, 17:12
А, ясно) Вообще у меня сейчас похожая ситуация. После того как прошёл 30 уровней JR, делал тестовое задние на стажировку (простое вэб-приложение с функциями CRUD), чуть с ума не сошёл сколько пришлось всего прочитать.
Теперь вот попал на обучение в T-sys, а там за 2 месяца надо сделать полноценный проект с кучей функционала (упрощённую кальку с реального проекта, выполнявшегося в компании), авторизацией, аутентификацией, разграничением ролей… Всё разрабатываешь сам: фронт энд, бэкэнд, тесты, документацию. Короч голова кругом, на измене сижу(( А требования к кандидатам были — всего лишь хорошее знание Java SE!
imp
Уровень 31
21 марта 2017, 09:31
вопрос про обучение — вам читают лекции или есть наставники с которым нужно общаться?
GuitarFactor
Уровень 30
23 марта 2017, 21:52
Есть и лекции и наставники) Но от лекций обычно не легче. Если прийти без базовых знаний о чём будут говорить на лекции, вряд ли что-то можно понять. А вот наставники это да, очень ценный ресурс.
imp
Уровень 31
24 марта 2017, 09:52
как пройдете стажировку напишите потом об этом :)
svartberg
Уровень 30
17 марта 2017, 10:04
В t-systems 2 раза присылал резюме — ноль реакции. Мне кажется, что по возрасту не подошёл, хотя ограничений формальных нет.
GuitarFactor
Уровень 30
17 марта 2017, 10:32
Если Вы просто подавали заявку на junior разработчика, разумеется будет ноль реакции. Компания не набирает джуниоров, для этого при компании существует JavaSchool. Там джунов обучают сотрудники, и только потом могут взять на работу.
Если Вы всё же говорили о заявке в JavaSchool, то Вы в срок подали заявку?
svartberg
Уровень 30
17 марта 2017, 10:51
Да, я подавал на java school. И подавал в срок, где-то в середине февраля ещё через их форму. Потом ближе к концу февраля они ещё на HH выкладывали объявление, и я через НН им подавал.
Общался ещё с Deutche Bank, у них тоже была школа в том году, но они от неё отказались и берут теперь только выпускников и студентов, на стажировку, мотивировав это тем, что им нужны лучшие. И как. Понял, такие как я, кто окончил ВУЗ не в этом году, а пару лет назад — особо не нужны на стажировках.
GuitarFactor
Уровень 30
17 марта 2017, 11:10
Гм, вообще говоря странно… Сейчас со мной в группе обучаются люди разного возраста. Самый младший участник — студент 4 курса, самому старшему, думаю, уже за 40.
imp
Уровень 31
17 марта 2017, 14:37
такой вопрос, а английский они как проверяли?
GuitarFactor
Уровень 30
17 марта 2017, 14:44
В самом конце собеседования спросили уровень английского и попросили сказать пару слов о своей прошлой работе. Запредельных требований к уровню английского не было (может потому что домашние задания и тест на компьютере в классе были полностью на английском)
svartberg
Уровень 30
17 марта 2017, 08:02
А не подскажите, что за компания? Я сейчас сам пытаюсь найти, куда можно податься, но пока даже на собеседования не приглашают.
GuitarFactor
Уровень 30
17 марта 2017, 09:48
Это T-Systems.
Если не приглашают, может быть Вы не достаточно рассылаете своё резюме? Попробуйте активно рассылать его по компаниям, которые ищут джунов или миддлов. В 10-15 компаний в день. Рано или поздно куда-нибудь да пригласят, не расстраивайтесь. На JavaRush 2.0 на тему поиска работы есть отличные статьи в разделе «Стажировка»)