Рефлексия: решение "нетрадиционных" задачЯ не буду слишком сильно все разжевывать, т.к. сама идея рефлексии не имеет ничего хитрого, просто об этом механизме часто забывают. Человек, писавший что-то сложнее копипаста примеров, должен догадаться моментально по паре объяснений и примеров. Рефлексия - это, говоря простыми словами, способ обращаться программе к собственному коду. Само понятие рефлексии в программировании сейчас используется в контексте "управляемого кода" - кода, который выполняется в интерпретаторе, а не напрямую, как в компилируемых языках. Рефлексией пользуются относительно не часто, но такой способ проектирования имеет большие преимущества по сравнению со стандартными паттернами проектирования. Рефлексия позволяет делать код крайне модульным без перекомпиляции, что имеет отдельное значение в "управляемом коде", в котором нету возможности (как в C/C++/ASM и т.д.) получить прямой доступ к любому месту в памяти и переписать. Типичное использование рефлексии - это загрузка нужного класса или метода, исходя из поступающих данных, чтобы при добавлении нового функционала не надо было дописывать новые условия в if или switch. Несколько простых примеров использования такого подхода на JAVA и PHP. <? $processor = new RequestProcessor(); $funcname = RequestProcessor::FUNC_PREFIX.$_GET['action']; if(method_exists($processor, $funcname)) { echo $processor->$funcname($xpath, $name[0]); } // в PHP подгружать классы динамически можно через встроенные механизмы: // http://php.net/manual/en/language.oop5.autoload.php ?>
Class clazz = null; try { clazz = Class.forName("some.package.TheActionsClass"); Object obj = clazz.newInstance(); Method actionMethod = clazz.getDeclaredMethod(anAction); String result = (String) actionMethod.invoke(obj); System.out.println("result: "+result); } catch ( ClassNotFoundException | InstantiationException | IllegalAccessException | NoSuchMethodException | InvocationTargetException e) { e.printStackTrace(); } // в JAVA загружаемые классы должны входить в classpath при старте приложения Нельзя говорить о рефлексии в Java, не упомянув об аннотациях.
clazz = Class.forName("some.package.SomeExampleClass"); for (Method method : clazz.getDeclaredMethods()) { if (method.getAnnotation(OnTimerTick.class) != null) { method.invoke(this); } } Далее: как можно этот механизм использовать для "нетрадиционных" задач. Сама структура организации скомпилированного кода (байт-кода) достаточно проста и уже сама по себе может дать какую-то информацию о приложении без декомпиляции - будь то jar (zip папки, по сути) или просто файлы классов. Более того, даже код, прошедший обфускацию, содержит в скомпилированном виде паттерны, которые могут быть использованы, например, антивирусами. Чем тут может помочь рефлексия? Рефлексия в java позволяет создавать собственный загрузчик классов, где на входе мы получаем бинарный поток данных, а на выходе должны предоставить экземпляр искомого класса. Таким образом, собственно, байт-код может быть закриптован любым способом, на который только хватит фантазии. В данной папке приведен самый простой вариант такого загрузчика. Код состоит из 2-х частей:
В качестве шифрования сугубо для примера используется BASE64. Такая пара криптограф-загрузчик позволяет зашифровать и загружать любой скомпилированный класс-файл. Несложная доработка позволит, таким образом, паковать в единый файл целую структуру классов. Где это может быть полезно? Исходники: sources/KostaPC/reflection/java_reflection_encoder
|