Итак, вчера мы с вами поиграли в джавовский вариант «Интеллектуальное казино против знатоков», и при этом, при всем уважении кам, телезрители выиграли! Если же я вдруг упустил знатоков, решивших вчера хотя бы три задачи — пишите мне в личку, и награда найдет своего героя!
Вчера нас с телезрителями обвинили в том, что большинство вчерашних задач были связаны с Java весьма косвенно. Мы принимаем это обвинение, и поэтому сегодня у нас вариант на чистой Java! никаких спрингов, эксэмэлей и паттернов. Это будет настоящее испытание для истинных любителей хардкора!
Под катом — ответы на вчерашний раунд и суперблиц! Против знатоков сегодня играет телезритель из Петербурга Андрей apangin Паньгин.
Но сначала ответы на вчерашние задачи.
Скомпилируется ли следующий аспект AJC компилятором?
Если да — то что он выведет на консоль при компиляции?public aspect QuizAspect { public static int count(int i) { return i++; } before (int n) : execution(public int QuizAspect.count(int)) && args(n) && if(QuizAspect.count(1)>1) { System.out.println("QuizAspect " + n); } }
Правильный ответ. Скомпилируется успешно, но ничего не выведет на консоль при компиляции. При этом вызов метода Quiz.count в рантайме приведет к StackOverflowError ошибке!
Можно подумать, что выражение в if() начнет выпоняться при компиляции кода, но это не так.
(не стоит путать аспекты с мета программированием)
Аспект лишь встроит код совета внутрь метода count, добавит if() к этому коду.
В чём подвох удалять Java-комментарии таким выражением? Укажите 3 причины, почему так делать нельзя. (считаем, что исходник написан нормальными символами) —
Pattern.compile("/\*(?:[^*]|\*[^/])*\*/")
Ответ
- Если это джавовская строка, а в ней якобы комент — то не будет работать
- Если комент заканчивается на две звездочки слэш, то работать не будет
- Если комментарий большой, то получим Будет StackOverflowError, т.к. java regexp’ы используют backtracking.
Пофиксить можно двумя способами:
- Possessive quantifier:
Pattern.compile("/\*(?:[^*]|\*[^/])*+\*/")
- Independent group:
Pattern.compile("/\*(?>,[^*]|\*[^/])*\*/")
Есть 2 Spring контекста:
1. a.xml с бином
<util:list id="myList"> <value>3</value> <value>4</value> </util:list>
2. b.xml с бином
<util:list id="myList"> <value>6</value> </util:list>
Что напечатает такой фрагмент кода:
System.out.println(new ClassPathXmlApplicationContext("a.xml", "b.xml").getBean("myList"));
И как можно заставить его бросить ошибку, не изменяя логику работы кода?
Ответ
Выведет 6, а заставить бросить ошибку можно установив allowBeanDefinitionOverriding у контекста в false.
А теперь самая хардкорная задача вчерашнего дня, по мнению президента, премьера и министра обороны элитарного клуба.
Ниже приведены 2 программы. Каждая из них пытается аллоцировать суммарно памяти больше размера хипа. Но одна из них выкидывает java.lang.OutOfMemoryError, а вторая нет. Почему?
public class OOM1 { private static final int SIZE = (int) (Runtime.getRuntime().maxMemory() * 0.55); public static void main(String[] args) { { byte[] bytes = new byte[SIZE]; System.out.println(bytes.length); } byte[] bytes1 = new byte[SIZE]; System.out.println(bytes1.length); System.out.println("I allocated memory successfully"); } } public class OOM2 { private static final int SIZE = (int) (Runtime.getRuntime().maxMemory() * 0.35); public static void main(String[] args) { { byte[] bytes = new byte[SIZE]; System.out.println(bytes.length); } byte[] bytes1 = new byte[SIZE]; System.out.println(bytes1.length); byte[] bytes2 = new byte[SIZE]; System.out.println(bytes2.length); System.out.println("I allocated memory successfully"); } }
Ответ
В обоих случаях javac понимает, что переменная bytes не будет использована после окончание внутреннего блока. Поэтому второй созданный массив, который мы кладем в переменную bytes1, займет тот же слот, что и переменная bytes. Как следствие, после выполнения присваивания bytes1 < — new bytes[SIZE] значение, которое было в переменной bytes становится недоступным и GC может его удалить. Тем самым OOM2 требует всего лишь 70% от хипа, а не 105%.
Желающие узнать ответы — попробуйте написать им в личку. Может быть они сжалятся над вами!
Суперблиц от Андрея Паньгина
Вот и настало время истинного хардкора! Знатоки поднимают глаза вверх, и на их экранах появляется улыбающийся apangin. Он кагбэ машит всем знатоками и кидает им тысячи воздушных поцелуев.
Вопрос первый
Что не так с этим кодом? Как его исправить?
public static double[] getRandomVector(int size) { double[] vector = new double[size]; Arrays.parallelSetAll(vector, i -> Math.random()); return vector; }
Вопрос второй
Как такое может быть, что публичный метод работает заметно быстрее идентичного приватного?
public class Modifiers { static final Inner inner = new Inner(); static class Inner { int x = 1; int getX1() { return x; } int getX2() { return getX1(); } int getX3() { return getX2(); } int getX4() { return getX3(); } int getX5() { return getX4(); } int getX6() { return getX5(); } int getX7() { return getX6(); } int getX8() { return getX7(); } int getX9() { return getX8(); } private int getPrivate() { return getX9(); } public int getPublic() { return getX9(); } } @Benchmark public int testGetPrivate() { return inner.getPrivate(); } @Benchmark public int testGetPublic() { return inner.getPublic(); } }
Вопрос третий
Можно ли в Java создать класс (именно класс, не интерфейс) без единого конструктора, даже приватного?
Такие дела!
Ваши ответы пишите ниже в комментариях под спойлером. У вас есть 12 часов. Решившие все три задачи получат специальный приз от Андрея и JUG.ru.
Ответы — традиционно на хабре, но уже после JPoint.
Удачи!
Автор: 23derevo