Почему стек работает по принципу LIFO, а не FIFO
Что проверяют
Понимаете ли, что LIFO это не произвольный выбор, а следствие того, как вложены вызовы функций. От вас ждут объяснения через время жизни кадра, а не пересказа определения. Для Android сюда же ложится стек возврата экранов.
Как отвечать
Начать с того, что LIFO и есть определение стека, поэтому вопрос на самом деле другой: почему для вызовов функций выбрали такую дисциплину. Ответ в том, что вызовы строго вложены. Если a вызвала b, а b вызвала c, то завершится сначала c, потом b, потом a. Времена жизни кадров вложены друг в друга, и последний созданный всегда умирает первым.
Из этого следует главное преимущество: выделение памяти сводится к сдвигу одного указателя. Кадр кладётся сверху, на выходе указатель возвращается назад, и вся память кадра освобождается разом, без поиска свободного блока и без фрагментации. Очередь такого не даёт: при FIFO снимать пришлось бы самый нижний кадр, то есть тот, который ещё нужен, и освобождение оставляло бы дыры в середине.
Дальше полезно показать, что структура выбирается под порядок обработки. LIFO нужен там, где надо вернуться к отложенному состоянию: обход в глубину, разбор скобок и выражений, отмена действия, стек возврата экранов. FIFO нужен там, где важна очерёдность: очередь сообщений главного потока, пул задач, буфер событий.
Где спотыкаются
Пересказывают определение вместо причины. Фраза «последний пришёл, первый вышел» не отвечает на вопрос «почему», отвечают вложенность вызовов и дешёвое освобождение памяти.
Путают стек вызовов и стек возврата в Android. Второй это список записей задачи, которым управляет система, и его поведение меняется флагами запуска и режимом запуска активити, так что кнопка «назад» возвращает не всегда на предыдущий экран.
Третье: в коде берут класс Stack из старой части стандартной библиотеки. Он унаследован от Vector, синхронизирован без нужды и перебирается снизу вверх, то есть в порядке, обратном снятию. Для стека и для очереди сейчас берут ArrayDeque.