5

Eclipse (Eclipse コンパイラーを使用) では、Java 7 言語機能をいくつか使用しながら、Java 6 クラス ファイルを作成できることがわかりました。以下の画像では、Java 6 クラス ファイルとして正常にコンパイルされた 2 つの Java 7 言語機能を確認できます。ただし、コメントアウトされているその他の Java 7 機能はコンパイルされません。

私の推測では、Eclipse は、どの Java 7 言語機能が Java 6 JVM と互換性があり、どれが互換性がないかを判断していると思います。たとえば、ジェネリック型の JComboBox は単なるコンパイル機能 (実行時ではない) であるため、どのように互換性があるか想像できます。文字列の切り替え機能は、バイトコードに違いをもたらし、新しいJVM機能に依存していると思いますが、間違っている可能性があります...

私の質問:

  • Eclipse は、どの Java 7 言語機能が Java 6 クラス ファイルにコンパイル可能で、どれがそうでないかを判断できるほど賢いのでしょうか?

  • 以下の例は明らかに 1.6 ソース互換ではないのに、なぜ「ソース互換」を 1.6 に設定してもエラーにならないのでしょうか?

  • この「トリック」により、Java 7 言語機能の少なくとも一部を使用しながら、Java 6 クラス ファイルを作成できるようです。ソース 1.7 とターゲット 1.6 で javac を使用すると失敗しますが、なぜこれが機能するのですか? Ecilpse コンパイラには、javac にはない機能がありますか?

ここに画像の説明を入力

比較のために、予想どおり Java 6 コンパイラに切り替えたときの結果を次に示します。

ここに画像の説明を入力

4

4 に答える 4

1

Eclipse がこれを許可する理由や、これが単なるバグなのかはわかりません。1.7javacはそれを教えてくれます

error: strings in switch are not supported in -source 1.6

また、なぜJComboBox機能するのかわかりませんが、

System.out.println(new JComboBox<String>() {}.getClass().getGenericSuperclass());

> javax.swing.JComboBox<java.lang.String>

そこにあってはならない実行時の一般的な情報があります。IMO が非互換として拒否された場合に、ジェネリックではないクラスにジェネリックを使用できるようにします。ただし、JVM6 では上記のコードを実行しませんでした。たぶん、クラッシュすることさえあります。

しかし、少なくともswitch技術的には問題ありません。http://www.benf.org/other/cfr/java7switchonstring.htmlは、これが単なるコンパイラのトリックであり、新しい言語機能、API、またはバイトコードを必要としないことを示しています。

少し単純化した例:

int java7(String string) {
    switch (string) {
        case "BB":
            return 12;
        case "FRED":
            return 13;
    }
    return 0;
}

本質的になる

int java6(String string) {
    switch (string.hashCode()) {
        case 2112:
            if (string.equals("BB"))
                return 12;
            break;
        case 2166379:
            if (string.equals("FRED"))
                return 13;
            break;
    }
    return 0;
}

String#hashCode()これは、 の結果が指定されており、変更してはならないという事実に基づいています。コンパイラは、正当なコードをより速く書くための時間を節約します。

同じことがひし形演算子にも当てはまります。たとえばnew ArrayList<>()、コンパイラによって簡単に解決できます。

同じセミ7の互換性を可能にするAndroidツールを使用すると、それを使用できます。ただし、違いは、Java 7 を対象とした.class ファイルを使用することです。とにかく、Android は .class ファイルを内部形式に変換する必要があるため、.class から .dex コンパイラーは、入力が機能するものを使用して、Android ランタイムが理解できる命令を生成できます。

たとえば、try-with-resource はAutoCloseable、Java 6 には存在しなかったインターフェイスが必要なため、機能しません。

また、Lambda 式などの特別な機能には、新しいタイプのバイトコードも必要です。

于 2014-10-30T17:37:14.323 に答える
1

次の 2 つのことが起こっていると思います。

  1. JComboBoxJava 1.6の代わりにJava 1.7rt.jarがリンクされているため、最初の行(ジェネリックを使用)が機能すると思われrt.jarます(JavaSE-1.6でセットアップされたプロジェクトがあり、その場合、最初の行は最初の組み合わせでもコンパイルされません設定の)。ただし、これは言語バージョンの問題ではなく、クラス ライブラリの問題です。(Java アプリを実行時よりもjavac新しいものに対してコンパイルした場合でも、多くの問題が発生する可能性があります)。rt.jar

  2. 2 行目は、おそらく Eclipse コンパイラーのバグを表しています。Java 7 の新しい言語機能のほとんどは純粋にコンパイラで実装できますが (Android は 2013 年後半から実装されています)、それを行うと Java 6 とのソース互換性がないことは明らかです。

つまり、(おそらく) 通常とは異なる Eclipse 構成で少なくとも 1 つのバグを発見したということです。注意して、それに依存しないでください。

于 2014-10-30T15:47:11.880 に答える
0

これは、プロジェクトのビルド パスで構成されている JRE システム ライブラリが、選択したコンプライアンス レベルと一致していないことが原因である可能性があります。一般に、ほとんどの場合、プロジェクトのコンパイラ設定で [実行環境からのコンプライアンスを使用する] オプションを選択する必要があります。プロジェクトのビルド パスを確認し、JRE システム ライブラリを実行環境として指定したかどうかを確認します。

于 2014-10-30T17:14:16.303 に答える
0

私の推測では、ECJ が Java 6 に設定されたときに何かをコンパイルし、他のものをコンパイルしない理由について正しいと思います。ジェネリックはキャストと同じものにコンパイルされるだけなので、ターゲットが Java 6 に設定されている場合に機能するのはなぜでしょうか?

javac と Eclipse コンパイラーの違いは何ですか? を参照してください。javac と ECJ のその他の違いについては、

于 2014-10-30T15:23:33.470 に答える