2013-04-22 12 views
139

Java 8では、ラムダ式などの重要な新しい言語機能が導入されています。Java 7コードをJava 7 JVMで実行するようにコンパイルできますか?

コンパイルされたバイトコードが大幅に変更され、レトロトランスレータを使用しないでJava 7仮想マシン上で実行できないような変更がありますか?

+0

可能な複製[Javaバージョン間の後方互換性の具体例はありますか?](http://stackoverflow.com/questions/1654923/are- Javaの間の後方互換性のない特定の例) –

答えて

113

いいえ、ソースコードで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 
+4

いいえ、私はそう思わないでしょう。 Javaはデスクトップ市場のシェアはわずかですが、そのシェアはかなり狭いです。しかし、それは新しいバージョンと機能の採用を妨げています。私はローカルJavaインストールをアップグレードしなくてもいいので、かなり長い間、私が書いたコードでJava 8の機能を使用することはできません。 – JesperE

+0

なぜですか? 「はい」は、Java 8がJava 7 VMで実行するようにコンパイルできることを意味しますが、これはJava 8コンパイラによれば正しくありません。 – JesperE

+5

今私は参照してください:あなたの "いいえ"は、問題の見出しではなく、質問の本文に答えます。 – Abdull

31

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

おそらく、次の参考資料は、何とかラムダに関連する変更がどのように計測されているかを理解するのを助けることができます。

これらは、物事は、ボンネットの下にインストルメントされているかを詳細に説明します。おそらくあなたはそこにあなたの質問に対する答えを見つけることができます。

+6

新しいバイトコードはありませんが、新しい構造体はありません。検証者がうんざりします。 –

+0

@exabrial、 "構造"とはどういう意味ですか? – Abdull

+11

良い例はInterfacesです。彼らは今メソッドを含むことができます。 Java7ベリファイアにはこれを処理する機能がありません。すべての古いバイトコードが使用されますが、新しい方法で使用されます。 –

49

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

必要なAPIクラスが存在すれば、LambdaはそのままJava 7でも実行できます。 invokedynamic命令はJava 7上に存在しますが、コンパイル時にラムダクラスを生成するようにラムダを実装することができました(初期のJDK 8ビルドはそうしました)。その場合、Javaバージョンで動作します。 (Oracleは将来のプルーフィングにlambdaにinvokedynamicを使用することにしましたが、多分いつかはJVMがファーストクラスの機能を持つため、lambdaごとにクラスを生成する代わりにinvokedynamicを使用してパフォーマンスを向上させることができます)Retrolambdaはそれらの呼び出されたすべての動的命令を処理し、それらを匿名クラスに置き換えること。実行時にlamdba invokedynamicが初めて呼び出されたときのJava 8の動作と同じです。

Repeating Annotationsは構文上の砂糖です。以前のバージョンとバイトコード互換です。 Java 7では、反復アノテーションを含むコンテナアノテーションの実装の詳細を隠すヘルパーメソッド(例:getAnnotationsByType)を実装するだけで済みます。

私の知る限り、Type Annotationsはコンパイル時にのみ存在するので、彼らは彼らが

のJava 7で動作させるのに十分でなければならないので、ちょうどJavaの8-コンパイルされたクラスのバイトコードのバージョン番号を変更し、バイトコードの変更を必要とすべきではありませんMethod parameter namesはJava 7のバイトコードに存在するため、互換性もあります。メソッドのバイトコードを読み込み、メソッドのデバッグ情報内のローカル変数名を調べることで、それらにアクセスできます。例えば、Spring Frameworkは@PathVariableを実装するのとまったく同じですから、おそらくあなたが呼び出すことのできるライブラリメソッドがあります。抽象インターフェースメソッドはメソッド本体を持たないため、そのデバッグ情報はJava 7のインターフェースメソッドには存在せず、AFAIKもJava 8には存在しません。

The other new featuresはほとんど新しいAPIで、HotSpotとツーリングが改善されました。新しいAPIの一部は、第三者のライブラリとして利用できます(例:ThreeTen-Backportおよびstreamsupport)。

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

+0

VM 1.7で実行するコードを実際にコンパイルする方法に関する情報を補足できますか? –

+0

@MaciejChałapuk補足。 –

+0

私はそれを各機能ごとに別々に動作させる方法の詳細を期待していました。 Retrolambdaは別の答えで言及されています。 –

-4

-source 1.7 -target 1.7を実行するとコンパイルされます。しかし、lambdaのようなJava 8固有の機能を持っていればコンパイルされません

関連する問題