web-dev-qa-db-ja.com

Java 8コードをコンパイルしてJava 7 JVMで実行できますか?

Java 8では、ラムダ式などの重要な新しい言語機能が導入されています。

言語のこれらの変更は、レトロ翻訳機を使用せずにJava 7仮想マシンで実行されることを妨げるようなコンパイル済みバイトコードの大きな変更を伴いますか?

159

いいえ、ソースコードで1.8の機能を使用するには、1.8 VMをターゲットにする必要があります。新しいJava 8リリースを試し、-target 1.7 -source 1.8でコンパイルしようとしましたが、コンパイラは拒否します。

$ javac Test -source 1.8 -target 1.7
javac: source release 1.8 requires target release 1.8
137
JesperE

デフォルトのメソッドでは、Java 7では実行できなかったバイトコードとJVMの変更が必要です。Java 7以下のバイトコード検証では、メソッド本体とのインターフェースが拒否されます(静的初期化メソッドを除く)。デフォルトメソッドはサブクラスでオーバーライドできるため、呼び出し側でデフォルトメソッドを静的メソッドでエミュレートしようとしても同じ結果は得られません。 Retrolambda は、デフォルトメソッドのバックポートのサポートを制限していますが、新しいJVM機能を本当に必要とするため、完全にバックポートすることはできません。

必要なAPIクラスが存在する場合、LambdasはそのままJava 7で実行できます。 invokedynamic命令はJava 7に存在しますが、コンパイル時にラムダクラスを生成するようにラムダを実装することが可能でした(初期のJDK 8ビルドはそのようにした)。任意のJavaバージョン。 (オラクルは、将来の証明のためにラムダにinvokedynamicを使用することを決定しました;いつかJVMがファーストクラスの機能を持つため、invokedynamicをラムダごとにクラスを生成する代わりに使用するように変更できるため、パフォーマンスが向上します)これらのすべてのinvokedynamic命令を処理し、それらを匿名クラスに置き換えます。 lamdba invokedynamicが最初に呼び出されたときにJava 8が実行時に行うことと同じです。

注釈の繰り返し は単なる構文上の砂糖です。以前のバージョンとバイトコード互換性があります。 Java 7では、ヘルパーメソッド(たとえば getAnnotationsByType )を自分で実装する必要があります。このメソッドは、繰り返されるアノテーションを含むコンテナアノテーションの実装の詳細を非表示にします。

AFAIK、 Type Annotations はコンパイル時にのみ存在するため、バイトコードの変更は不要であるため、Java 8コンパイル済みクラスのバイトコードバージョン番号を変更するだけで十分です。それらはJava 7.で動作します。

メソッドパラメーター名 バイトコードにJava 7が存在するため、これも互換性があります。メソッドへのアクセスを取得するには、メソッドのバイトコードを読み取り、メソッドのデバッグ情報でローカル変数名を調べます。たとえば、Spring Frameworkは @ PathVariable を実装するために正確に実行するため、おそらく呼び出し可能なライブラリメソッドがあります。抽象インターフェイスメソッドにはメソッド本体がないため、そのデバッグ情報はJava 7のインターフェイスメソッドには存在せず、Java 8にもありません。

その他の新機能 は、ほとんどが新しいAPI、HotSpotの改善、およびツールです。一部の新しいAPIは、サードパーティライブラリとして利用できます(例: ThreeTen-Backport および streamsupport )。

要約すると、デフォルトのメソッドには新しいJVM機能が必要ですが、他の言語機能には必要ありません。それらを使用する場合は、Java 8でコードをコンパイルし、 Retrolambda を使用してバイトコードをJava 5/6 /に変換する必要があります。 7フォーマット。少なくともバイトコードのバージョンを変更する必要があり、javacは-source 1.8 -target 1.7を許可しないため、レトロ翻訳が必要です。

55
Esko Luontola

私の知る限り、JDK 8のこれらの変更では、新しいバイトコードを追加する必要はありませんでした。ラムダインスツルメンテーションの一部は、invokeDynamic(JDK 7にすでに存在します)を使用して行われています。したがって、JVM命令セットの観点からは、コードベースの互換性を損なうものは何もありません。ただし、以前のJDKでJDK 8からのコードをコンパイル/実行するのが困難になる可能性のあるAPI関連の多くの改善とコンパイラの改善があります(ただし、私はこれを試していません)。

次の参考資料は、ラムダに関連する変更がどのようにインスツルメントされているかについての理解を深めるのに役立つ可能性があります。

これらは、物がフードの下でどのように装備されるかを詳細に説明します。おそらく、あなたはあなたの質問に対する答えをそこで見つけることができます。

31
Edwin Dalorzo

「retrotranslator」を使用する場合は、Esko Luontolaの優れたRetrolambdaを試してください。 https://github.com/orfjackal/retrolambda

11
Stefan Zobel