私は小さなライブラリに取り組んでいます。明らかな理由で、[今すぐに推測するモジュールを除いて] Java 11のすべての機能を使用してコードを生成したいのですが、Java 8以上。
私がこれを試すとき:
javac -source 11 -target 1.8 App.Java
次のメッセージが表示されます。
warning: source release 11 requires target release 11
...バイトコードを見ると、クラスのバージョンが0x37
(Java 11)であることがわかります。
$ xxd App.class
00000000: cafe babe 0000 0037 ...
そして、Java 8はそれをロードできません:
Exception in thread "main" Java.lang.UnsupportedClassVersionError: App has been
compiled by a more recent version of the Java Runtime (class file version 55.0),
this version of the Java Runtime only recognizes class file versions up to 52.0
at Java.lang.ClassLoader.defineClass1(Native Method)
at Java.lang.ClassLoader.defineClass(ClassLoader.Java:763)
at Java.security.SecureClassLoader.defineClass(SecureClassLoader.Java:142)
at Java.net.URLClassLoader.defineClass(URLClassLoader.Java:468)
at Java.net.URLClassLoader.access$100(URLClassLoader.Java:74)
at Java.net.URLClassLoader$1.run(URLClassLoader.Java:369)
at Java.net.URLClassLoader$1.run(URLClassLoader.Java:363)
at Java.security.AccessController.doPrivileged(Native Method)
at Java.net.URLClassLoader.findClass(URLClassLoader.Java:362)
at Java.lang.ClassLoader.loadClass(ClassLoader.Java:424)
at Sun.misc.Launcher$AppClassLoader.loadClass(Launcher.Java:349)
at Java.lang.ClassLoader.loadClass(ClassLoader.Java:357)
at Sun.launcher.LauncherHelper.checkAndLoadMain(LauncherHelper.Java:495)
どのようにしてそのような互換性を提供しますか?すべてのビルドツールを利用できます。
私にとっては、高水準言語(Java)を低水準言語(バイトコード)に変換するだけで簡単に思えます。高水準言語が変わっても、低水準言語は変わらないはずです。だからこそ可能だと思った。
[〜#〜]更新[〜#〜]
みんな、この答えは重複しないと思います OpenJDK-11に移動しますが、Java 8 でコンパイルします。なぜなら、OPはコードを生成し続ける方法を尋ねるからです。 Java 8
の機能ですが、Java 11をターゲットにしています(これは、有名な下位互換性です)。私の質問はその逆です。Java 11でコードを生成したいのですが、Java 8をターゲットにしたいと思います。質問する前にトピックを調査していたときに、その質問に出くわしました。私の状況に適用できるとは思いませんでした。
他の質問 Java 8コードをコンパイルしてJava 7 JVM で実行できるかどうかは私の質問と似ていますが、2013年に尋ねられました。 Java 7とJava 8の間でバイトコードが明らかに変更されました。
Java 8以来、バイトコードはそれほど変わっていないと思いました。そのため、この質問をしました。
JDK 11向けにコンパイルされたクラスをJDK 8に変換することは、理論的には高度なツールで可能ですが、簡単ではありません。バイナリレベルで重要な変更があります。
最初に、JDK 11は nest タイプを導入しました。これにより、内部/外部クラスのprivate
メンバーにアクセスするときに合成アクセサーメソッドを生成する必要がなくなります。もちろん、そのようなアクセスは古いバージョンでは失敗します。
また、 動的定数 も導入しましたが、Java言語がその機能をどこで利用しているかはわかりません。これは主に将来のバージョンを対象としています。
次に、JDK 9以降、文字列連結はinvokedynamic
を使用してコンパイルされます Java.lang.invoke.StringConcatFactory
Java 8には存在しません。
機能する可能性のある機能は、インターフェースのprivate
メソッドであり、Java 9で言語機能として導入されましたが、Java 8ではすでにバイナリレベルで処理されていました。
Java 8もモジュール定義を処理できませんが、おそらく無視されます。
Javacのjavadocで明示的なものは何もありませんでしたが、-sourceオプションと-targetオプションの両方に同じバージョンしか指定できないと思います。 Java 11の機能はJava 8ではサポートされていませんが、その逆は当てはまりますが、より高いJavaバージョンはコンパイルされたコードを実行できます以前のバージョンでは、Java 11で書かれたコードをコンパイルしてJava 8.で実行できるようにすることはできません。
私はここで間違っている可能性がありますが、少なくとも今のところ、javacはそのように使用するためのものではありません。
ここで少し推測してみましょう:--release 8 --target 8
は機能します(--source 11
パラメータ)。
しかし、これがうまくいくとは思えません。 javacにはN個のソースコード機能を受け入れるサポートがなく、以前のターゲットバージョンに逆コンパイルされたと思います。
もちろん、コンパイラーは、N個のソースコードを(N-m)バイトコードに変換するために必要な変換についての知識を持つことができます。しかし、それはコンパイラーをはるかに複雑にし、各リリースはそれに追加されます。 testingの取り組みに劇的なコストも追加されます。コンパイラのメンテナがそれに喜んで同意することはないでしょう。これは広く使用されているユースケースではないようです。
だから、のみ "解決策"は知っています:分岐と二重メンテナンス。そして、物事を合理的に保つために、私は単にJava 8バージョン、およびたぶん Java 11。
いいえ、Java 11ソースをJava 8バイナリにコンパイルすることはできません。
javac
の用語では、-source
パラメータを-target
パラメータより大きくすることはできません。
したがって、Java 8バイナリを生成する場合、ソースはJava 8(またはそれ以前)で作成する必要があります。何も使用しない場合= Java 11言語機能。ソースは基本的にすでにJava 8なので、これはあまり大きな問題にはなりません。
JDK 11を使用してJava 8ソースをJava 8バイナリにコンパイルできます。JDKバージョン) canは、ソースおよび/またはターゲットのバージョンよりも大きいことができます。
注:javacドキュメントでは、-source
パラメータを-target
パラメータ以下にする必要があることについては何も述べられていません。ただし、非公式のドキュメントはたくさんあります。たとえば、 https://stackoverflow.com/a/9261298/691074
私が知る限り、実際にそのような状況が機能するようにする単一の反例もありません。