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

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

Ответ 1

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

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

Ответ 2

Обновление:

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


Да, это возможно, потому что я на самом деле написал это. Он не делает часть 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$$ (который воспроизводит себя и переписывается на Quine$$$ и т.д.).

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

Ответ 3

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

Вот пример для quine в Java.

Ответ 4

Программы, которые воспроизводят себя или программы саморепликации, называются 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);}} 

Ответ 5

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

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

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

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

Ответ 6

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

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

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

Ответ 7

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

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

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

Ответ 8

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

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

    или

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