Добавить в корзинуПозвонить
Найти в Дзене

Вопросы отсеивающего собеседования (с HR) на позицию автотестировщика java в Тинькофф (Т-банк)

volatile — это ключевое слово в языке программирования Java, которое применяется только к полям класса (включая статические поля), которые являются примитивными типами данных или ссылками на объекты (т.е. не для всех видов переменных) и предназначено для обеспечения видимости изменений этой переменной между различными потоками. Если во время ответа попросят развить тему, можно привести сравнение volatile и synchronized: volatile: Применяется только к полям класса(поля класса - переменные, объявленные на уровне класса, но вне методов, конструкторов или блоков). Гарантирует видимость изменений переменной между потоками. Не блокирует потоки, поэтому не может использоваться для защиты критических секций. Не обеспечивает атомарность операций с переменной. synchronized: Применяется к методам и блокам кода. Обеспечивает взаимное исключение: только один поток может выполнять синхронизированный метод или блок кода в определенный момент времени. Может использоваться для защиты критических секций
Оглавление

1. К чему применяется volatile?

volatile — это ключевое слово в языке программирования Java, которое применяется только к полям класса (включая статические поля), которые являются примитивными типами данных или ссылками на объекты (т.е. не для всех видов переменных) и предназначено для обеспечения видимости изменений этой переменной между различными потоками.

Если во время ответа попросят развить тему, можно привести сравнение volatile и synchronized:

volatile:

Применяется только к полям класса(поля класса - переменные, объявленные на уровне класса, но вне методов, конструкторов или блоков).

Гарантирует видимость изменений переменной между потоками.

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

Не обеспечивает атомарность операций с переменной.

synchronized:

Применяется к методам и блокам кода.

Обеспечивает взаимное исключение: только один поток может выполнять синхронизированный метод или блок кода в определенный момент времени.

Может использоваться для защиты критических секций и обеспечения атомарности операций.
Подробнее о потокобезопасности прочитайте здесь.
Подробнее о volatile и synchronized прочитайте здесь.

2. Нужно ли применять throws к RuntimeExceptions?

В языке программирования Java нет необходимости явно указывать throws для исключений, являющихся подтипами RuntimeException. Это связано с тем, что RuntimeException и его подклассы относятся к так называемым "непроверяемым" (unchecked) исключениям.

Непроверяемые исключения — это исключения, которые могут возникнуть в ходе выполнения программы, но компилятор не требует их явной обработки или объявления в сигнатуре метода. В отличие от проверяемых (checked) исключений, непроверяемые исключения могут быть проигнорированы при разработке, и их обработка остается на усмотрение программиста.

Примеры непроверяемых исключений:
NullPointerException
ArrayIndexOutOfBoundsException
IllegalArgumentException
ClassCastException
ArithmeticException
NumberFormatException
UnsupportedOperationException
IllegalStateException
IndexOutOfBoundsException
NegativeArraySizeException

Подробнее об исключениях в java почитайте в статье Что такое исключение в Java? Как его обрабатывать?

3. Назови поля LinkedList (в java)?

В Java-классе LinkedList есть следующие поля:

transient int size: Поле, которое хранит текущее количество элементов в списке.

transient Node<E> first: Ссылка на первый узел списка. Это начало списка.

transient Node<E> last: Ссылка на последний узел списка. Это конец списка.

static class Node<E>: Вложенный статический класс, представляющий узел списка. Каждый узел содержит три поля:E item — значение, хранимое в узле.
Node<E> next — ссылка на следующий узел.
Node<E> prev — ссылка на предыдущий узел.

Модификатор transient используется для того, чтобы эти поля не были сериализованы, если объект LinkedList будет сериализован. Это связано с тем, что структура может быть легко восстановлена из элементов списка.

Таким образом, LinkedList в Java состоит из цепочки объектов типа Node<E>, которые связывают элементы между собой через next и prev ссылки, а также имеет поля для отслеживания размера списка и ссылок на первый и последний узлы.

4. Можно ли и если можно то как изменить тип возвращаемого значения при переопределении метода (java)?

В Java вы можете изменить тип возвращаемого значения при переопределении метода, но с определёнными ограничениями. Это называется ковариантным возвращаемым типом.

Что такое ковариантный возвращаемый тип?
Ковариантный возвращаемый тип позволяет методам переопределять возвращаемое значение, если новый тип возвращаемого значения является подклассом (наследником) типа, указанного в методе суперкласса.
Важные моменты:

  • Тип возвращаемого значения в переопределённом методе должен быть подтипом оригинального типа, указанного в методе базового класса.
  • Параметры метода и его сигнатура (имя метода и типы параметров) должны оставаться такими же, как и у метода из суперкласса.
    Пример:

5. Какие типы данных хранятся на куче, а какие в стеке?

Куча (Heap) используется для хранения объектов, их полей (как экземплярных, так и статических), массивов и других динамически создаваемых структур данных.

Стек (Stack) используется для хранения локальных примитивных переменных, ссылок на объекты, а также для управления вызовами методов.

6. Как создать коллекцию примитивных типов, например int (с маленькой буквы) в java? Можно ли так ArrayList<int>?


В Java нельзя создать коллекцию примитивных типов, таких как int, double, char и т.д., напрямую. Java коллекции, такие как ArrayList, работают с объектами, а не с примитивными типами.
Для использования примитивных типов в коллекциях Java предоставляет соответствующие классы-оболочки (wrapper classes). Для типа int используется класс-оболочка Integer. Следовательно, вместо ArrayList<int> вы должны использовать ArrayList<Integer>.

7. Что такое Consumer и Supplier?

Consumer и Supplier — это функциональные интерфейсы в Java, которые представляют собой два из наиболее часто используемых интерфейсов в функциональном программировании.

Consumer — это функциональный интерфейс, который представляет собой операцию, принимающую один входной аргумент и не возвращающую результат. Он используется, когда нужно выполнить какое-то действие с объектом, но не требуется возвращать результат.

-2


Supplier — это противоположный Consumer функциональный интерфейс, представляющий собой операцию, которая не принимает никаких аргументов, но возвращает результат. Он используется, когда нужно предоставить (или "поставить") какое-то значение.

-3

8. Что возвращает промежуточный метод Стрима (java)?

В Java Stream API существуют два типа операций: промежуточные (intermediate) и терминальные (terminal).

Промежуточные методы стрима всегда возвращают новый стрим, что позволяет выстраивать цепочки операций ("stream pipeline").
Основные промежуточные методы включают:

filter(Predicate<T> predicate) — возвращает новый стрим, состоящий из элементов, соответствующих условию.

map(Function<T, R> mapper) — возвращает новый стрим, состоящий из результатов применения функции к каждому элементу исходного стрима.

flatMap(Function<T, Stream<R>> mapper) — возвращает новый стрим, состоящий из элементов стрима, полученных в результате применения функции и раскрытия вложенных стримов.

distinct() — возвращает новый стрим, состоящий из уникальных элементов исходного стрима.

sorted() или sorted(Comparator<T> comparator) — возвращает новый стрим, элементы которого отсортированы естественным порядком или с использованием указанного компаратора.

peek(Consumer<T> action) — возвращает новый стрим, состоящий из тех же элементов, но позволяет выполнить действие над каждым элементом без изменения стрима.

Так как все промежуточные методы стрима возвращают стрим, они не выполняют операции сразу, а лишь описывают цепочку операций. Реальное выполнение происходит только при вызове терминальной операции, такой как collect(), forEach(), reduce() и другие.

9. Как ограничить тип данных, с которым дженерик может работать только с наследниками определенного класса или реализациями интерфейса (в java)?

Вы можете ограничить тип параметра дженерика для работы только с наследниками определенного класса или реализациями интерфейса с помощью ключевого слова extends в объявлении дженерика.
Пример:

-4
-5

Вместо оглавления. Что вы найдете на канале QA Helper - справочник тестировщика?

Не забудьте подписаться на канал, чтобы не пропустить полезную информацию: QA Helper - справочник тестировщика

Пишите в комментариях какой пункт было бы интересно рассмотреть более подробно.

Также будет интересно почитать: Вопросы которые задают на собеседовании тестировщикам