java 自我复制的程序

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2617792/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-29 22:02:44  来源:igfitidea点击:

Programs that reproduces itself

javaquine

提问by Ming-Tang

Is it possible to make a Java program that prints its source code to a new file, and compiles it, and runs the compiled program?

是否可以制作一个 Java 程序,将其源代码打印到一个新文件中,然后编译它,然后运行编译后的程序?

采纳答案by M.A. Hanin

Yes, it is possible. A trivial implementation would be: have the source code contain itself in a string, save the string to a file and fill its own string with the same string (otherwise, the initial string would be of infinite size, due to the recursive manner of this implementation), compile the file, and run the compiled file (which will, in turn, do the very same).

对的,这是可能的。一个简单的实现是:让源代码将自身包含在一个字符串中,将该字符串保存到一个文件中并用相同的字符串填充它自己的字符串(否则,由于递归方式,初始字符串将是无限大的)实现),编译文件,然后运行编译的文件(反过来,它会做同样的事情)。

Non-trivial implementations are significantly harder.

非平凡的实现要困难得多。

回答by polygenelubricants

Update:

更新:

Okay, might as well make it autorun. Enjoy the madness. Run at your own risk.

好吧,不妨让它自动运行。享受疯狂。运行风险自负。



Yes it's possible, because I actually wrote it up. It doesn't do the RUN part (that's just too crazy, because as others have mentioned, it will cause an infinite loop),but here it is: Quine.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);
   }
}

So here's how to get the craziness to start:

所以这里是如何开始疯狂:

  • javac Quine.javato compile
  • java Quineto run it
    • It will produce, compile and run Quine$
  • I've made sure Quine.javais as readable as possible, so the majordifference from Quine$.javaare formatting and the 3x replace. The minordifference is that Quine$.javahas outset to Quine$$.
  • Quine$will produce, compile and run Quine$$
  • Quine$$will produce, compile and run Quine$$$
  • Quine$$$will produce, compile and run Quine$$$$
  • ...
  • javac Quine.java编译
  • java Quine运行它
    • 它将产生、编译和运行 Quine$
  • 我已经确保Quine.java尽可能可读,所以主要区别Quine$.java在于格式和 3x replace。该未成年人不同的是,Quine$.java已经out设置为Quine$$
  • Quine$将产生、编译和运行 Quine$$
  • Quine$$将产生、编译和运行 Quine$$$
  • Quine$$$将产生、编译和运行 Quine$$$$
  • ...

Do note that this doesn't do any reverse-engineering or cheat by reading the .javasource code, etc. Quineis a quine-generator because it produces a different code differently formatted, but Quine$is pretty much a true self-contained quine: it does reproduce itself, it just relabels it Quine$$(which reproduces itself and relabels to Quine$$$etc).

请注意,这不会通过阅读.java源代码等进行任何逆向工程或作弊。它Quine是一个 quine 生成器,因为它生成不同格式的不同代码,但Quine$几乎是一个真正的自包含 quine:它确实会复制它本身,它只是重新标记它Quine$$(复制自身并重新标记为Quine$$$等)。

So technically there's no infinite loop: it will eventually come to a halt when the file system can't handle another $. I was able to manually stop the madness by forcefully deleting all Quine$*files, but run at your own risk!!!

所以从技术上讲,没有无限循环:当文件系统无法处理另一个$. 我能够通过强行删除所有Quine$*文件来手动停止疯狂,但风险自负!!!

回答by Andreas Dolk

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

确定它有效 - 查看rosetta 代码并导航到 Quine,这是一个自引用程序,无需任何外部访问,即可输出自己的源代码

There's one example for a quine in Java.

在 Java 中有一个 quine 的例子。

回答by 09Q71AO534

Programs that reproduces itself or Self Replicating Programs are known as Quine Programs

自我复制的程序或自我复制的程序被称为Quine 程序

Sample Program in Javawhich reproduces itself.

复制自身的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);
     }

}

Output:

输出:

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);}} 

回答by Pascal Thivent

You could use the Java Compiler API (JSR-199) for this. Below, code from the JSR-199 that compiles code from a String (slightly modified to make it compile). The code actually compiles source code from the Stringinto a byte array (i.e. it doesn't write to disk), loads it and then executes it via reflection:

您可以为此使用 Java Compiler API (JSR-199)。下面是来自 JSR-199 的代码,它从字符串编译代码(稍微修改以使其编译)。代码实际上将源代码从 编译String成字节数组(即它不写入磁盘),加载它然后通过反射执行它:

That could be a starting point (credits to Peter Van der Ahé, the original author).

这可能是一个起点(作者 Peter Van der Ahé,原作者)。

BTW, you need of course a JDK to use this API.

顺便说一句,你当然需要一个 JDK 来使用这个 API。

回答by Martijn Courteaux

I don't know exactly what you want, but I think BeanShellis something you can use. BeanShell is an interpreter. You can run uncompiled Java-code (So you give it a String with code and he runs it).

我不知道你到底想要什么,但我认为BeanShell是你可以使用的东西。BeanShell 是一个解释器。你可以运行未编译的 Java 代码(所以你给它一个带有代码的字符串,然后他运行它)。

Of course if you really want to do what you wrote, the machine where the program is running needs a JDK to compile your program.

当然,如果你真的想做你写的东西,运行程序的机器需要一个JDK来编译你的程序。

Hope this helps

希望这可以帮助

回答by Midhat

I dont think it will work in Java. Wouldn't that involve overwriting a running class file.

我不认为它会在 Java 中工作。这不会涉及覆盖正在运行的类文件。

Suppose your program is in Quine.java compiled to Quine.class.

假设您的程序在 Quine.java 中编译为 Quine.class。

Now Quine.class will attempt to write its output to Quine.java (so far so good), and compile it to Quine.class. This is gonna be a problem as Quine.class is already running

现在 Quine.class 将尝试将其输出写入 Quine.java(到目前为止一切顺利),并将其编译为 Quine.class。这将是一个问题,因为 Quine.class 已经在运行

回答by Bert F

Yes - don't forget to use a JDK instead of a JRE:

是的 - 不要忘记使用 JDK 而不是 JRE:

  1. Bundle the app's source code files with the app. The app would copy the source files to a new set of source code files, compile the new source files, bundle the new source code with the new class files into a new app, and then spawn the new app.

    or

  2. Bundle a decompiler with the app. The app would run the decompiler on its own class files to generate new source code files, compile the new source files, bundle the decompiler with the new class files into a new app, and then spawn the new app.

  1. 将应用程序的源代码文件与应用程序捆绑在一起。该应用程序会将源文件复制到一组新的源代码文件中,编译新的源文件,将新的源代码与新的类文件捆绑到一个新的应用程序中,然后生成新的应用程序。

    或者

  2. 将反编译器与应用程序捆绑在一起。该应用程序将在其自己的类文件上运行反编译器以生成新的源代码文件,编译新的源文件,将反编译器与新的类文件捆绑到一个新的应用程序中,然后生成新的应用程序。

回答by Roberto Murphy

Here's a Java Quine using preview text block feature (-source 13 --enable-preview) where output is formatted the same as input:

这是一个使用预览文本块功能(-source 13 --enable-preview)的Java Quine,其中输出的格式与输入的格式相同:

package org.sample.quine;

public class QuineProgram
{
  public static void main(String...args)
  {
    String f ="""
package org.sample.quine;

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

Output:

输出:

package org.sample.quine;

public class QuineProgram
{
  public static void main(String...args)
  {
    String f ="""
package org.sample.quine;

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

Heavily Commented Version:

重磅评论版:

package org.sample.quine;

public class Quine
{
  public static void main(String...args)
  {
    // Inside text block use "" followed by token or token followed by "" so that we don't prematurely close text block
    String f ="""
package org.sample.quine;

public class Quine
{
  public static void main(String...args)
  {
    // Inside text block use "" followed by token or token followed by "" so that we don't prematurely close text block
    String f =""%c%c%s%1$c"";
    /* Tokens in template text block, each prefixed with percent symbol
     * 1(c)   third quote (34) of open block delimiter
     * 2(c)   new line    (10) of open block delimiter
     * 3(s)   String f         text block that goes between two text block delimiters
     * 4(1$c) first quote (34) of close block delimiter,
     *        1$ means first argument after template argument
     *        2$ would be second argument after template argument
     */
     // Arguments - 1 template (String f); 2 "; 3 newline; 4 template again without replacing tokens
     System.out.printf(f, 34, 10, f);
  }
}
""";
    /* Tokens in template text block, each prefixed with percent symbol
     * 1(c)   third quote (34) of open block delimiter
     * 2(c)   new line    (10) of open block delimiter
     * 3(s)   String f         text block that goes between two text block delimiters
     * 4(1$c) first quote (34) of close block delimiter,
     *        1$ means first argument after template argument
     *        2$ would be second argument after template argument
     */
    // Arguments - 1 template (String f); 2 "; 3 newline; 4 template again without replacing tokens
    System.out.printf(f, 34, 10, f);
  }
}