Каковы интересы синтетических методов?
проблема
Один друг предложил интересную проблему. Учитывая следующий код:
public class OuterClass {
private String message = "Hello World";
private class InnerClass {
private String getMessage() {
return message;
}
}
}
Из внешнего класса, как я могу распечатать message
переменное содержание? Конечно, изменение доступности методов или полей не допускается.
(источник здесь, но это французский блог)
Решение
Код для решения этой проблемы следующий:
try {
Method m = OuterClass.class.getDeclaredMethod("access$000", OuterClass.class);
OuterClass outerClass = new OuterClass();
System.out.println(m.invoke(outerClass, outerClass));
} catch (Exception e) {
e.printStackTrace();
}
Обратите внимание, что access$000
имя метода не является стандартным (даже если этот формат настоятельно рекомендуется), и некоторые JVM будут называть этот метод access$0
, Таким образом, лучшим решением является проверка синтетических методов:
Method method = null;
int i = 0;
while ((method == null) && (i < OuterClass.class.getDeclaredMethods().length)) {
if (OuterClass.class.getDeclaredMethods()[i].isSynthetic()) {
method = OuterClass.class.getDeclaredMethods()[i];
}
i++;
}
if (method != null) {
try {
System.out.println(method.invoke(null, new OuterClass()));
} catch (Exception e) {
e.printStackTrace();
}
}
Поэтому интересным моментом в этой проблеме является выделение использования синтетических методов. С помощью этих методов я могу получить доступ к закрытому полю, как это было сделано в решении. Конечно, мне нужно использовать рефлексию, и я думаю, что использование такого рода вещей может быть довольно опасным...
Вопрос
Каков интерес - для меня, как разработчика - синтетического метода? Какая может быть хорошая ситуация, когда использование синтетического может быть полезным?
3 ответа
Как вы продемонстрировали, модификаторы доступа Java являются просто информативными, и их можно обойти, используя отражение. Таким образом, ваши вопросы примерно эквивалентны "каков интерес обхода модификатора доступа?" Помимо злонамеренных целей, на ум приходит отладка; Вы можете, например, регистрировать внутреннее состояние некоторых библиотек извне библиотеки, не затрагивая сам код библиотеки вообще. Другой пример - сотрудничество с языками сценариев; если во время компиляции вы не знаете, какие классы и методы доступны, рефлексия может оказаться весьма полезной. Например, внутренности Jython используют огромное количество отражений вокруг.
Каков интерес для вас, как для разработчика, к синтетическому методу? Ну, во-первых, не вызывайте их (по причинам, объясненным другими ответчиками).
Но следует помнить одну интересную вещь, особенно если вы пишете код Java для запуска в среде, чувствительной к безопасности, и это то, что синтетические методы потенциально могут предоставить злоумышленникам задний ход к вашим закрытым полям.
Конечно, есть некоторые большие "если"- я имею в виду, необходимые условия - чтобы такая уязвимость имела значение:
- На самом деле злоумышленник должен запустить код в вашей JVM. В большинстве случаев это не проблема, потому что единственный выполняемый код - ваш.
- Код злоумышленника должен находиться в том же пакете, что и ваш внутренний класс (поскольку синтетический метод объявлен как закрытый для пакета).
- Код злоумышленника должен быть загружен из того же загрузчика классов, что и ваш класс. Если вы разрешаете запускать ненадежный код в своей JVM (условие #1), то для ненадежного кода лучше использовать отдельный загрузчик классов.
Вы никогда не должны вызывать синтетические методы доступа, использующие отражение, они могут изменяться в зависимости от того, какой компилятор вы используете. Например, запустить ваше решение на jdk1.6 на моем компьютере не удалось, так как access$000
метод не найден.
Синтетические средства доступа - это хакерский компилятор, позволяющий обойти тот факт, что внутренние классы были дополнением к Java 1.1, и спецификация VM никогда не менялась, чтобы приспособиться к ним.