Позвольте мне начать с небольшого теста Java.
Следующий код печатает «Hi, There»
Можете ли вы объяснить, как он это делает?
public class Test { public static void main(String args[]) { try { new ClassLoader() { public Class<?> findClass(String c) { byte[] bytecode = java.util.Base64.getDecoder().decode( "yv66vgAAADQAGAoABgAKCQALAAwIAA0KAA4ADwcAEAcAEQEABjxpb"+ "l0PgEAAygpVgEABENvZGUMAAcACAcAEgwAEwAUAQAJSGksIHRoZXJ"+ "lBwAVDAAWABcBAAFBAQAQamF2YS9sYW5nL09iamVjdAEAEGphdmEv"+ "bGFuZy9TeXN0ZW0BAANvdXQBABVMamF2YS9pby9QcmludFN0cmVhb"+ "TsBABNqYXZhL2lvL1ByaW50U3RyZWFtAQAHcHJpbnRsbgEAFShMam"+ "F2YS9sYW5nL1N0cmluZzspVgAhAAUABgAAAAAAAQABAAcACAABAAk"+ "AAAAZAAIAAQAAAA0qtwABsgACEgO2AASxAAAAAAAA"); return defineClass(“A”, bytecode, 0, bytecode.length); } }.loadClass(“A”).newInstance(); } catch (Exception e) { throw new RuntimeException(e); } } }
Ответ таков:
Он делает это, создавая новый класс A и создавая его экземпляры. Конечно, класс А выглядит примерно так:
public class A { public A() { System.out.println(“Hi, there”); } }
хотя, к сожалению, в Test.java вы не можете увидеть большую часть его кода.
Однако он присутствует в необработанном формате (байт-код), закодированном в строку base64.
Если вам интересно, строковое представление для A, как оно появляется в Test.java, может быть сгенерировано путем компиляции A.java и последующего доступа следующим образом:
URL url = A.class.getResource("A.class"); byte array[] = Files.readAllBytes(Paths.get(url.toURI())); String bytecode = Base64.getEncoder().encodeToString(array); System.out.println(bytecode); // this prints yv66vgAAADQAGAoAB…
В чем смысл ?
Итак, помимо невозможности чтения нашего кода (что очень плохо), есть ли какая-то польза от работы с необработанным байт-кодом, подобным этому?
Что ж, поскольку вы можете кодировать байт-код в фрагмент кода, теперь вы можете использовать другой подход к распространению своей работы и просить людей копировать и вставлять фрагмент кода в свою программу Java вместо того, чтобы загружать банка.
Конечно, этот подход подходит не всем, но в некоторых случаях он может оказаться полезным:
- демонстрации «попробуй, прежде чем использовать»
- Некоторые специализированные решения, в которых:
– ваша библиотека очень легкая и не имеет зависимостей (или только зависимости, которые вы можете предположить, что они присутствуют в среде при ее интеграции)
– ваш API минимален.
- Сервис вашего инструмента является чисто аддитивным (например, приложения для мониторинга, профилировщики, анализаторы покрытия, регистраторы событий и т. д.).
Реальный пример
Я использовал этот подход в nudge4j.
nudge4j — это инструмент мониторинга для java-приложений, который обычно используется во время разработки.
Метод копирования/вставки показался мне идеальным.
Спасибо, что прочитали это.