Продолжаем исследовать способы
выстрелить себе в ногу на Java. Ещё одна головоломка с уже известного нам
сайта.
Иногда бывает такое, что я просыпаюсь только для того, чтобы понять, что на самом-то деле я всё ещё сплю. Каждый раз, когда это случается, я чувствую себя несколько не в своей тарелке. Чтобы этого избежать, я начал считать уровни рекурсии, погружаясь в сон:
public class Sleeper {
private int level;
public synchronized int enter(Dream dream) {
level++;
try {
dream.dream(this);
} finally {
level--;
}
return level;
}
}
Выглядит надёжно, не так ли? Погружаясь в сон, я увеличиваю счётчик. Выходя из сна, я уменьшаю его. Благодаря блоку
finally
я уверен, что не забуду уменьшить счётчик, даже если на каком-то уровне рекурсии очередной сон выбросит исключение. Поскольку метод объявлен
synchronized
, я не боюсь, что в мой сон влезет какой-то другой поток.
Теперь я со спокойной душой ложусь спать следующим образом:
public class Main {
public static void main(String[] args) {
if (new Sleeper().enter(new Dream()) != 0) {
// The goal is to reach this line
System.out.println("Am I still dreaming?");
}
}
}
Есть ли ошибка в моих рассуждениях? Можно ли написать такой класс
Dream
, что он сломает мою программу, и она напечатать помеченную строку? Изменять классы
Sleeper
и
Main
нельзя.
public class Dream {
public void dream(Sleeper s) {
// TODO implement me
}
}
Действуют те же ограничения, что и в
задаче про клоунов. Вкратце, нельзя использовать reflection и манипулировать байт-кодом на лету. В остальном можете писать неограниченно грязный код, при условии, конечно, что компилятор его съест.