Программы, которые воспроизводят себя

Можно ли сделать программу Java, которая выводит исходный код в новый файл и компилирует его, и запускает скомпилированную программу?

Да, это возможно. Тривиальная реализация будет заключаться в следующем: иметь исходный код в строке, сохранить строку в файле и заполнить ее собственную строку той же строкой (в противном случае начальная строка будет иметь бесконечный размер из-за рекурсивного способа этого реализация), скомпилировать файл и запустить скомпилированный файл (который, в свою очередь, сделает то же самое).

Нетривиальные реализации значительно сложнее.

Обновить:

Хорошо, может также сделать это автозапуск. Наслаждайтесь безумием. Беги на свой страх и риск.


Да, это возможно, потому что я на самом деле написал это. Он не делает часть RUN (это слишком сумасшествие, потому что, как говорили другие, это вызовет бесконечный цикл), но вот оно: Quine.java

 import java.io.*; public class Quine { public static void main(String[] args) throws Exception { char q = 34; String out = "Quine$"; String text = ( "import java.io.*; " + "public class [OUT] { " + "public static void main(String[] args) throws Exception { " + "char q = 34; String out = `[OUT]$`; String text = `[TEXT]`; " + "PrintWriter pw = new PrintWriter(out + `.java`); " + "pw.format(text, 34, out, text); " + "pw.close(); Runtime runtime = Runtime.getRuntime(); " + "runtime.exec(`javac ` + out + `.java`).waitFor(); " + "runtime.exec(`java ` + out); " + "} " + "}" ).replace("`", "%1$c").replace("[OUT]", "%2$s").replace("[TEXT]", "%3$s"); PrintWriter pw = new PrintWriter(out + ".java"); pw.format(text, 34, out, text); pw.close(); Runtime runtime = Runtime.getRuntime(); runtime.exec("javac " + out + ".java").waitFor(); runtime.exec("java " + out); } } 

Итак, вот как начать безумие:

  • javac Quine.java для компиляции
  • java Quine для запуска
    • Он будет производить, компилировать и запускать Quine$
  • Я убедился, что Quine.java максимально читаем, поэтому основное отличие от Quine$.java – форматирование и replace 3x. Небольшая разница заключается в том, что Quine$.java имеет значение Quine$$ .
  • Quine$ будет производить, компилировать и запускать Quine$$
  • Quine$$ будет производить, компилировать и запускать Quine$$$
  • Quine$$$ будет производить, компилировать и запускать Quine$$$$

Обратите внимание, что это не делает никакой обратной инженерии или обманывает, читая исходный код .java и т. Д. Quine является quine-generator, потому что он создает другой код, отформатированный по-разному, но Quine$ в значительной степени является самодостаточным quine: он воспроизводит себя, он просто переносит его Quine$$ (который воспроизводит себя и переписывается с Quine$$$ т. д.).

Так что технически нет бесконечного цикла: он в конечном итоге остановится, когда файловая система не сможет обработать другой $ . Я смог вручную остановить безумие, решив удалить все файлы Quine$* , но бежать на свой страх и риск !!!

Конечно, это работает. Посмотрите на код розетки и перейдите к Quine, которая является самореферентной программой, которая без внешнего доступа может выводить свой собственный источник .

В Java есть один пример для quine.

Программы, которые воспроизводят себя или программы саморепликации, называются программами Quine

Пример программы на Java, которая воспроизводит себя.

 public class QuineProgram { public static void main(String[] args){ String f = "public class QuineProgram { " + "public static void main(String[] args)" + "{ String f =%c%s%1$c;" + " System.out.printf(f,34,f);}} "; System.out.printf(f, 34, f); } } 

Вывод:

 public class QuineProgram { public static void main(String[] args){ String f ="public class QuineProgram { public static void main(String[] args){ String f =%c%s%1$c; System.out.printf(f,34,f);}} "; System.out.printf(f,34,f);}} 

Для этого вы можете использовать Java Compiler API (JSR-199). Ниже приведен код из JSR-199, который компилирует код из String (слегка модифицированный, чтобы скомпилировать его). Код фактически компилирует исходный код из String в массив байтов (то есть он не записывается на диск), загружает его и затем выполняет его через reflection:

  • MemoryFileManager.java : файловый менеджер для компиляции строк в байтовые массивы.
  • ByteArrayClassLoader.java : загрузчик classов, который загружает classы из массивов байтов.
  • CompileFromString.java : class, который объединяет все вместе.

Это может быть отправной точкой (кредиты Питеру Ван дер Аэ, оригинальному автору).

Кстати, вам нужно, конечно, JDK использовать этот API.

Я не знаю точно, что вы хотите, но я думаю, что BeanShell – это то, что вы можете использовать. BeanShell является переводчиком. Вы можете запустить uncompiled Java-код (так что вы даете ему строку с кодом, и он запускает ее).

Конечно, если вы действительно хотите делать то, что вы написали, на машине, на которой работает программа, нужен JDK для компиляции вашей программы.

Надеюсь это поможет

Я не думаю, что он будет работать на Java. Не будет ли это связано с перезаписью запущенного файла classа.

Предположим, что ваша программа находится в Quine.java, скомпилированной в Quine.class.

Теперь Quine.class попытается записать свой вывод в Quine.java (насколько это хорошо) и скомпилировать его в Quine.class. Это будет проблемой, поскольку Quine.class уже запущен

Да – не забудьте использовать JDK вместо JRE:

  1. Свяжите файлы исходного кода приложения с приложением. Приложение скопирует исходные файлы в новый набор файлов исходного кода, скомпилирует новые исходные файлы, объединит новый исходный код с новыми файлами classов в новое приложение, а затем создаст новое приложение.

    или

  2. Свяжите декомпилятор с приложением. Приложение будет запускать декомпилятор в своих собственных файлах classов, чтобы генерировать новые файлы исходного кода, компилировать новые исходные файлы, связывать декомпилятор с новыми файлами classов в новом приложении, а затем запускать новое приложение.