ソースコードを新しいファイルに出力してコンパイルし、コンパイルされたプログラムを実行する Java プログラムを作成することは可能ですか?
9 に答える
アップデート:
さて、それを自動実行することもできます。狂気を楽しむ。ご自身の責任で実行してください。
はい、実際に書いたので可能です。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
はフォーマットと 3xreplace
です。小さな違いは、にQuine$.java
設定out
されていることQuine$$
です。Quine$
生成、コンパイル、実行しますQuine$$
Quine$$
生成、コンパイル、実行しますQuine$$$
Quine$$$
生成、コンパイル、実行しますQuine$$$$
- ...
これは、リバース エンジニアリングを行ったり、.java
ソース コードを読み取ってチートしたりしないことに注意してくださいそれ自体を再ラベル付けするだけです(それ自体を複製し、などに再ラベル付けします)。Quine
Quine$
Quine$$
Quine$$$
したがって、技術的には無限ループはありません。ファイル システムが別の$
. すべてのファイルを強制的に削除することで手動で狂気を止めることができましたQuine$*
が、自己責任で実行してください!!!
はい、可能です。簡単な実装は次のようになります: ソースコードに文字列にそれ自体を含め、その文字列をファイルに保存し、それ自体の文字列を同じ文字列で埋めます (そうしないと、この再帰的な方法により、最初の文字列は無限のサイズになります)実装)、ファイルをコンパイルし、コンパイルされたファイルを実行します (これは、まったく同じことを行います)。
自明ではない実装は非常に困難です。
確かに動作します - rosetta コードを見て、Quine に移動します。Quine は、外部アクセスなしで独自のソースを出力できる自己参照型プログラムです。
Java の quine の例が 1 つあります。
自分自身を複製するプログラムまたは自己複製プログラムは、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
バイト配列にコンパイルし (つまり、ディスクに書き込みません)、それをロードしてから、リフレクションを介して実行します。
MemoryFileManager.java
: 文字列をバイト配列にコンパイルするためのファイル マネージャー。ByteArrayClassLoader.java
: バイト配列からクラスをロードするクラスローダー。CompileFromString.java
: すべてをまとめるクラス。
それが出発点になる可能性があります (元の著者である Peter Van der Ahé の功績によるものです)。
ところで、この API を使用するにはもちろん JDK が必要です。
あなたが何を望んでいるのか正確にはわかりませんが、BeanShellはあなたが使えるものだと思います。BeanShell はインタープリターです。コンパイルされていない Java コードを実行できます (したがって、コードを含む文字列を指定すると、彼はそれを実行します)。
もちろん、自分が書いたものを本当に実行したいのであれば、プログラムを実行しているマシンには、プログラムをコンパイルするための JDK が必要です。
お役に立てれば
はい-JREの代わりにJDKを使用することを忘れないでください。
アプリのソースコードファイルをアプリにバンドルします。アプリは、ソースファイルを新しいソースコードファイルのセットにコピーし、新しいソースファイルをコンパイルし、新しいソースコードを新しいクラスファイルと一緒に新しいアプリにバンドルしてから、新しいアプリを生成します。
また
アプリに逆コンパイラーをバンドルします。アプリは、独自のクラスファイルで逆コンパイラを実行して、新しいソースコードファイルを生成し、新しいソースファイルをコンパイルし、逆コンパイラを新しいクラスファイルにバンドルして、新しいアプリを生成します。
私はそれがJavaで動作するとは思わない。実行中のクラスファイルを上書きする必要はありませんか。
プログラムが Quine.class にコンパイルされた Quine.java にあるとします。
ここで、Quine.class はその出力を Quine.java に書き込もうとし (これまでのところは問題ありません)、それを Quine.class にコンパイルします。Quine.class が既に実行されているため、これは問題になります。