Программы, воспроизводящие себя - PullRequest
18 голосов
/ 11 апреля 2010

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

Ответы [ 8 ]

23 голосов
/ 12 апреля 2010

Обновление:

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


Да, это возможно, потому что я действительно это написал. Он не выполняет роль 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 - форматирование и 3x replace. незначительное различие заключается в том, что Quine$.java имеет out, установленное в Quine$$.
  • Quine$ будет производить, компилировать и запускать Quine$$
  • Quine$$ будет производить, компилировать и запускать Quine$$$
  • Quine$$$ будет производить, компилировать и запускать Quine$$$$
  • ...

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

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

11 голосов
/ 11 апреля 2010

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

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

6 голосов
/ 11 апреля 2010

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

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

4 голосов
/ 13 августа 2015

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

Пример программы на 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);}} 
2 голосов
/ 12 апреля 2010

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

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

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

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

1 голос
/ 11 апреля 2010

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

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

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

0 голосов
/ 11 апреля 2010

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

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

    или

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

0 голосов
/ 11 апреля 2010

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

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

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

...