- PVSM.RU - https://www.pvsm.ru -
Всегда… Нет. Никогда не выходи в пургу [1] пиши такой код ни для чего, кроме подобных забав.
[2]
Гийом — lead разработки языка Groovy
Один мой друг — большой любитель головоломок. Всяких, и программистких в том числе. Вот его последняя забава:
Напишите нужный код в static initializer, чтобы assert перестал падать:
public class Test {
static {
//Write some code here
}
public static void main(String[] args) {
Integer a = 20;
Integer b = 20;
assert (a + b == 60);
}
}
Если вы решите попробовать, не забудьте включить assertions (флагом -ea) [3].
Дальше будет решение и кое какие рассуждения на тему, так что если вы уже справились, или вам влом -смело под кат.
Начнем с решения. Тут ничего особо сложного, просто нужно знать reflection и два факта о классе Integer:
Также нам нужно знать как этот кэш зовут и где он живет, но благодаря исходникам rt.jar это не проблема. Что бы вы думали? Этот кэш — закрытое (private) поле в закрытом внутреннем классе. Ура-ура.
Делать будем вот что:
Вот вам код:
static {
try {
Class<?>[] declaredClasses = Integer.class.getDeclaredClasses();
Field cacheField = declaredClasses[0].getDeclaredField("cache");
cacheField.setAccessible(true);
((Integer[]) cacheField.get(null))[20 + 128] = 30;
} catch (Exception e) { e.printStackTrace(); }
}
Не знаю как вам, а как по мне так — ужас-ужас. Уродливый код, который лезет куда не следует, нарушает правила видимости и энкапсуляцию (есть такое слово?), да и ломается с пол-пинка (например, стоит создать Integer-ы конструкторами, а не auto-boxing-ом).
Да и вообще, нам просто повезло, что у Integer-а есть этот кэш, который можно подкрутить. Иначе — никак нам этот финт с изменением плюса не провернуть.
Почему такую простую штуку так тяжело сделать? Потому что Java под такие вещи не заточена (она-же женского рода, правда?). Java — статический язык, и это прекрасно. Мы можем всегда расчитывать на то, что 20+20=40. Ну, почти всегда. Это хорошо.
Но что, если нам все таки нужно провернуть подобные трюки (не с переопределением поведения плюса, конечно, но похожие)? Для этого есть инструменты получше. Например — Groovy.
Вот версия головоломки на Groovy:
//Write some code here
Integer a = 20
Integer b = 20
assert 60 == a + b
Практически то же самое в головоломке (без безобразия с main(), дурацких точек-с-запятой и необходимости в -ea), но благодаря тому, что Groovy — динамический язык, решение совсем другое. Вот, что нужно знать:
Вот чего мы сделаем:
А всё! Вот код:
Integer.metaClass.plus = {int i -> 60 }
Тут, как говорится — без коментариев.
Автор: jbaruch
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/java/8005
Ссылки в тексте:
[1] Всегда… Нет. Никогда не выходи в пургу: http://www.imdb.com/title/tt0198781/quotes?qt=qt0457952
[2] Image: https://twitter.com/glaforge/status/204591355257819138
[3] включить assertions (флагом -ea): http://docs.oracle.com/javase/1.4.2/docs/guide/lang/assert.html#enable-disable
Нажмите здесь для печати.