Jawaban:
Ini adalah instruksi JVM baru yang memungkinkan kompiler untuk menghasilkan kode yang memanggil metode dengan spesifikasi yang lebih longgar daripada sebelumnya - jika Anda tahu apa itu " mengetik bebek ", invokedynamic pada dasarnya memungkinkan untuk mengetik bebek. Tidak terlalu banyak yang bisa Anda lakukan sebagai programmer Java; jika Anda seorang pembuat alat, Anda dapat menggunakannya untuk membangun bahasa berbasis JVM yang lebih fleksibel dan lebih efisien. Berikut ini adalah posting blog yang sangat manis yang memberikan banyak detail.
MethodHandle, yang benar-benar hal yang sama tetapi dengan lebih banyak fleksibilitas. Tetapi kekuatan sebenarnya dalam semua ini bukan berasal dari bahasa Jawa, tetapi pada kemampuan JVM sendiri dalam mendukung bahasa lain yang secara intrinsik lebih dinamis.
invokedynamicyang menjadikannya performant (dibandingkan dengan membungkusnya dalam kelas-anonim yang hampir menjadi satu-satunya pilihan sebelum memperkenalkan invokedynamic). Kemungkinan besar banyak bahasa pemrograman fungsional di atas JVM akan memilih untuk mengkompilasi ini daripada kelas-dalam-dalam.
Beberapa waktu lalu, C # menambahkan fitur keren, sintaks dinamis dalam C #
Object obj = ...; // no static type available
dynamic duck = obj;
duck.quack(); // or any method. no compiler checking.
Anggap saja sebagai sintaks gula untuk panggilan metode reflektif. Ini dapat memiliki aplikasi yang sangat menarik. lihat http://www.infoq.com/presentations/Statically-Dynamic-Typing-Neal-Gafter
Neal Gafter, yang bertanggung jawab untuk tipe dinamis C #, baru saja membelot dari SUN ke MS. Jadi tidak masuk akal untuk berpikir bahwa hal yang sama telah dibahas di dalam SUN.
Saya ingat segera setelah itu, beberapa pria Jawa mengumumkan sesuatu yang serupa
InvokeDynamic duck = obj;
duck.quack();
Sayangnya, fitur ini tidak dapat ditemukan di Java 7. Sangat kecewa. Untuk programmer Java, mereka tidak memiliki cara mudah untuk memanfaatkan invokedynamicprogram mereka.
invokedynamictidak pernah dimaksudkan untuk digunakan untuk programmer Java. IMO itu tidak sesuai dengan filosofi Java sama sekali. Itu ditambahkan sebagai fitur JVM untuk bahasa non-Jawa.
Ada dua konsep untuk dipahami sebelum melanjutkan ke invokedynamic.
1. Pengetikan Statis vs. Dynamin
Static - pengecekan tipe preforms pada waktu kompilasi (misal Java)
Dynamic - pemeriksaan tipe preforms saat runtime (mis. JavaScript)
Pengecekan tipe adalah proses memverifikasi bahwa suatu program adalah tipe aman, ini adalah, memeriksa informasi yang diketik untuk variabel kelas dan instance, parameter metode, nilai kembali, dan variabel lainnya. Misalnya Java tahu tentang int, String, .. pada waktu kompilasi, sedangkan jenis objek dalam JavaScript hanya dapat ditentukan saat runtime
2. Mengetik Kuat vs Lemah
Strong - menetapkan batasan pada jenis nilai yang disediakan untuk operasinya (mis. Java)
Lemah - mengkonversi (melemparkan) argumen operasi jika argumen tersebut memiliki tipe yang tidak kompatibel (mis. Visual Basic)
Mengetahui bahwa Java adalah jenis yang Statically and Weakly typed, bagaimana Anda mengimplementasikan bahasa yang diketik secara Dinamis dan Kuat pada JVM?
Invokedynamic mengimplementasikan sistem runtime yang dapat memilih implementasi metode atau fungsi yang paling tepat - setelah program dikompilasi.
Contoh: Memiliki (a + b) dan tidak tahu apa-apa tentang variabel a, b pada waktu kompilasi, invokedynamic memetakan operasi ini ke metode yang paling tepat di Java saat runtime. Misalnya, jika ternyata a, b adalah Strings, maka panggil metode (String a, String b). Jika ternyata a, b adalah ints, maka panggil metode (int a, int b).
invokedynamic diperkenalkan dengan Java 7.
Sebagai bagian dari artikel Java Records saya, saya mengartikulasikan tentang motivasi di balik Inoke Dynamic. Mari kita mulai dengan definisi kasar dari Indy.
Invoke Dynamic (Juga dikenal sebagai Indy ) adalah bagian dari JSR 292 yang bermaksud untuk meningkatkan dukungan JVM untuk Dynamic Type Languages. Setelah rilis pertama di Java 7, invokedynamicopcode beserta java.lang.invokekopernya digunakan cukup luas oleh bahasa berbasis JVM dinamis seperti JRuby.
Meskipun indy dirancang khusus untuk meningkatkan dukungan bahasa dinamis, indy menawarkan lebih dari itu. Sebenarnya, ini cocok untuk digunakan di mana pun perancang bahasa membutuhkan segala bentuk dinamika, dari akrobat tipe dinamis hingga strategi dinamis!
Misalnya, Java 8 Lambda Expressions sebenarnya diimplementasikan menggunakan invokedynamic, meskipun Java adalah bahasa yang diketik secara statis!
Untuk beberapa waktu JVM mendukung empat tipe pemanggilan metode: invokestaticmemanggil metode statis, invokeinterfacememanggil metode antarmuka, invokespecialmemanggil konstruktor, super()atau metode pribadi dan invokevirtualmemanggil metode instan.
Terlepas dari perbedaan mereka, tipe doa ini memiliki satu sifat yang sama: kita tidak dapat memperkaya mereka dengan logika kita sendiri . Sebaliknya, invokedynamic memungkinkan kita untuk Bootstrap proses doa dengan cara apa pun yang kita inginkan. Kemudian JVM menangani memanggil Metode Bootstrapped secara langsung.
Pertama kali JVM melihat invokedynamicinstruksi, ia memanggil metode statis khusus yang disebut Metode Bootstrap . Metode bootstrap adalah bagian dari kode Java yang telah kami tulis untuk menyiapkan logika yang akan dipanggil:
Kemudian metode bootstrap mengembalikan instance dari java.lang.invoke.CallSite. Ini CallSitememegang referensi ke metode aktual, yaitu MethodHandle.
Mulai sekarang, setiap kali JVM melihat invokedynamicinstruksi ini lagi, ia melompati Slow Path dan secara langsung memanggil executable yang mendasarinya. JVM terus melewati jalur lambat kecuali ada perubahan.
Java 14 Recordsmenyediakan sintaksis kompak yang bagus untuk mendeklarasikan kelas yang seharusnya menjadi pemegang data bodoh.
Mempertimbangkan catatan sederhana ini:
public record Range(int min, int max) {}
Bytecode untuk contoh ini akan menjadi sesuatu seperti:
Compiled from "Range.java"
public java.lang.String toString();
descriptor: ()Ljava/lang/String;
flags: (0x0001) ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: invokedynamic #18, 0 // InvokeDynamic #0:toString:(LRange;)Ljava/lang/String;
6: areturn
Dalam Tabel Metode Bootstrapnya :
BootstrapMethods:
0: #41 REF_invokeStatic java/lang/runtime/ObjectMethods.bootstrap:
(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;
Ljava/lang/invoke/TypeDescriptor;Ljava/lang/Class;
Ljava/lang/String;[Ljava/lang/invoke/MethodHandle;)Ljava/lang/Object;
Method arguments:
#8 Range
#48 min;max
#50 REF_getField Range.min:I
#51 REF_getField Range.max:I
Jadi metode bootstrap untuk Records disebut bootstrapyang berada di java.lang.runtime.ObjectMethodskelas. Seperti yang Anda lihat, metode bootstrap ini mengharapkan parameter berikut:
MethodHandles.Lookupmewakili konteks pencarian (Bagian Ljava/lang/invoke/MethodHandles$Lookup).toString, equals, hashCode, dll) bootstrap yang akan untuk nge-link. Misalnya, ketika nilainya adalah toString, bootstrap akan mengembalikan a ConstantCallSite( CallSiteyang tidak pernah berubah) yang menunjuk ke toStringimplementasi aktual untuk Catatan khusus ini.TypeDescriptormetode ( Ljava/lang/invoke/TypeDescriptor
bagian).Class<?>, mewakili tipe kelas Rekam. Dalam
Class<Range>kasus ini.min;max.MethodHandleper komponen. Dengan cara ini metode bootstrap dapat membuat MethodHandleberbasis pada komponen untuk implementasi metode khusus ini.The invokedynamicinstruksi melewati semua argumen mereka dengan metode bootstrap. Metode bootstrap, pada gilirannya, mengembalikan sebuah instance dari ConstantCallSite. Ini ConstantCallSitememegang referensi untuk implementasi metode yang diminta, misalnya toString.
Berbeda dengan Reflection APIs, java.lang.invokeAPI ini cukup efisien karena JVM dapat sepenuhnya melihat semua permintaan. Karena itu, JVM dapat menerapkan segala macam optimasi selama kita menghindari jalan lambat sebanyak mungkin!
Selain argumen efisiensi, invokedynamicpendekatan ini lebih dapat diandalkan dan kurang rapuh karena kesederhanaannya .
Selain itu, bytecode yang dihasilkan untuk Java Records tidak tergantung pada jumlah properti. Jadi, bytecode lebih sedikit dan waktu startup lebih cepat.
Akhirnya, anggaplah versi baru Java menyertakan implementasi metode bootstrap baru dan lebih efisien. Dengan invokedynamic, aplikasi kami dapat memanfaatkan peningkatan ini tanpa kompilasi ulang. Dengan cara ini kita memiliki semacam Kompatibilitas Biner Teruskan . Juga, Itulah strategi dinamis yang sedang kita bicarakan!
Selain Java Records, dinamis yang dipanggil telah digunakan untuk mengimplementasikan fitur-fitur seperti:
LambdaMetafactoryStringConcatFactory
meth.invoke(args). Jadi bagaimanainvokedynamiccocoknyameth.invoke?