Java 8 memperkenalkan fitur-fitur bahasa baru yang penting seperti ekspresi lambda.
Apakah perubahan dalam bahasa ini disertai dengan perubahan signifikan dalam bytecode yang dikompilasi yang akan mencegahnya dijalankan pada mesin virtual Java 7 tanpa menggunakan retrotranslator?
Jawaban:
Tidak, menggunakan 1,8 fitur dalam kode sumber Anda mengharuskan Anda menargetkan 1,8 VM. Saya baru saja mencoba rilis Java 8 baru dan mencoba kompilasi
-target 1.7 -source 1.8
, dan kompiler menolak:sumber
Metode default memerlukan perubahan pada bytecode dan JVM yang tidak mungkin dilakukan di Java 7. Verifikasi bytecode Java 7 dan di bawahnya akan menolak antarmuka dengan badan metode (kecuali untuk metode initializer statis). Mencoba meniru metode default dengan metode statis di sisi penelepon tidak akan menghasilkan hasil yang sama, karena metode default dapat ditimpa dalam subkelas. Retrolambda memiliki dukungan terbatas untuk backporting metode default, tetapi tidak pernah dapat sepenuhnya didukung karena benar-benar membutuhkan fitur JVM baru.
Lambdas dapat berjalan di Java 7 apa adanya, jika kelas API yang diperlukan hanya akan ada di sana. Instruksi invokedynamic ada di Java 7, tetapi akan mungkin untuk mengimplementasikan lambdas sehingga menghasilkan kelas lambda pada waktu kompilasi (build JDK 8 awal melakukannya seperti itu) dalam hal ini akan bekerja pada versi Java apa pun. (Oracle memutuskan untuk menggunakan invokedynamic untuk lambdas untuk pembuktian di masa depan; mungkin suatu hari JVM akan memiliki fungsi kelas satu, jadi invokedynamic dapat diubah untuk menggunakannya daripada menghasilkan kelas untuk setiap lambda, sehingga meningkatkan kinerja.) Yang dilakukan Retrolambda adalah bahwa itu memproses semua instruksi invokedynamic dan menggantinya dengan kelas anonim; sama seperti apa yang dilakukan Java 8 saat runtime ketika lamdba invokedynamic disebut pertama kali.
Pengulangan Anotasi hanyalah gula sintaksis. Mereka bytecode kompatibel dengan versi sebelumnya. Di Java 7 Anda hanya perlu menerapkan sendiri metode pembantu (mis. GetAnnotationsByType ) yang menyembunyikan detail implementasi anotasi wadah yang berisi anotasi berulang.
AFAIK, Jenis Anotasi hanya ada pada waktu kompilasi, jadi mereka seharusnya tidak memerlukan perubahan bytecode, jadi hanya mengubah nomor versi bytecode dari kelas Java 8 yang dikompilasi harus cukup untuk membuatnya bekerja di Java 7.
Nama parameter metode ada dalam bytecode dengan Java 7, jadi itu juga kompatibel. Anda dapat mengaksesnya dengan membaca bytecode metode dan melihat nama variabel lokal di informasi debug metode. Sebagai contoh, Spring Framework melakukan hal itu untuk mengimplementasikan @PathVariable , jadi mungkin ada metode pustaka yang bisa Anda panggil. Karena metode antarmuka abstrak tidak memiliki tubuh metode, informasi debug itu tidak ada untuk metode antarmuka di Java 7, dan AFAIK tidak di Java 8.
Fitur-fitur baru lainnya kebanyakan adalah API baru, peningkatan pada HotSpot dan tooling. Beberapa API baru tersedia sebagai perpustakaan pihak ketiga (mis. ThreeTen-Backport dan streamsupport ).
Summa summarum, metode standar membutuhkan fitur JVM baru tetapi fitur bahasa lainnya tidak. Jika Anda ingin menggunakannya, Anda harus mengkompilasi kode di Java 8 dan kemudian mengubah bytecode dengan format Retrolambda ke Java 5/6/7. Minimal versi bytecode perlu diubah, dan javac tidak diizinkan
-source 1.8 -target 1.7
sehingga diperlukan retrotranslator.sumber
Sejauh yang saya tahu tidak ada perubahan di JDK 8 yang mengharuskan penambahan bytecodes baru. Bagian dari instrumentasi lambda sedang dilakukan dengan menggunakan
invokeDynamic
(yang sudah ada di JDK 7). Jadi, dari sudut pandang set instruksi JVM, tidak ada yang harus membuat basis kode tidak kompatibel. Ada, meskipun, banyak API yang terkait dan peningkatan kompiler yang akan membuat kode dari JDK 8 sulit dikompilasi / dijalankan di bawah JDK sebelumnya (tapi saya belum mencoba ini).Mungkin bahan referensi berikut dapat membantu memperkaya pemahaman tentang bagaimana perubahan yang terkait dengan lambda sedang diinstrumentasi.
Ini menjelaskan secara rinci bagaimana hal-hal diinstruksikan di bawah tenda. Mungkin Anda dapat menemukan jawaban untuk pertanyaan Anda di sana.
sumber
class C extends A with B
, diimplementasikan dengan antarmuka normalA
danB
dan kelas pendampingA$class
danB$class
. kelasC
hanya meneruskan metode ke kelas pendamping statis. Tipe-diri tidak dipaksakan sama sekali, lambda ditransformasikan pada waktu kompilasi ke dalam kelas-kelas dalam abstrak, demikian juganew D with A with B
ungkapan. Pencocokan pola adalah sekelompok struktur if-else. Pengembalian non-lokal? mekanisme coba-tangkap dari lambda. Ada yang tersisa? (Menariknya, scalac saya mengatakan 1,6 adalah default)Jika Anda bersedia menggunakan "retrotranslator", cobalah Retrolambda Esko Luontola yang luar biasa: https://github.com/orfjackal/retrolambda
sumber
Anda dapat melakukannya
-source 1.7 -target 1.7
kemudian akan dikompilasi. Tapi itu tidak akan dikompilasi jika Anda memiliki fitur khusus java 8 seperti lambdassumber
-source 1.7
tidak akan terbang.