Программы, который размножается

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

18
задан Ming-Tang 11 April 2010 в 16:45
поделиться

7 ответов

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

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

11
ответ дан 30 November 2019 в 06:39
поделиться

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

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

    или

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

0
ответ дан 30 November 2019 в 06:39
поделиться

Sure it works - Have a look at rosetta code and navigate to Quine, which is a self-referential program that can, without any external access, output its own source.

Есть один пример quine на Java.

6
ответ дан 30 November 2019 в 06:39
поделиться

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

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

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

2
ответ дан 30 November 2019 в 06:39
поделиться

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

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

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

1
ответ дан 30 November 2019 в 06:39
поделиться

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

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

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

0
ответ дан 30 November 2019 в 06:39
поделиться

Обновление:

Ладно, можно было бы сделать автозапуск. Наслаждайтесь безумием. Запускайте на свой страх и риск.


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

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

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

23
ответ дан 30 November 2019 в 06:39
поделиться
Другие вопросы по тегам:

Похожие вопросы: