Kata pengantar
Semua kode dalam artikel ini ditulis dalam JavaScript, tetapi Anda juga dapat menggunakan bahasa skrip yang kompatibel dengan JSR 223 lainnya. Contoh -contoh ini dapat dijalankan sebagai file skrip atau dalam shell interaktif dengan menjalankan satu pernyataan pada satu waktu. Sintaks untuk mengakses properti dan metode objek dalam JavaScript adalah sama dengan bahasa Java.
Artikel ini berisi bagian -bagian berikut:
1. Akses Kelas Java
Untuk mengakses tipe asli atau referensi tipe Java di JavaScript, Anda dapat memanggil fungsi Java.type() , yang mengembalikan jenis objek yang sesuai berdasarkan pada nama kelas penuh yang diteruskan. Kode berikut menunjukkan cara mendapatkan jenis objek yang berbeda:
var arraylist = java.type ("java.util.arraylist"); var inttype = java.type ("int"); var stringArrayType = java.type ("java.lang.string []"); var int2darraytype = java.type ("intring []"); Metode mengembalikan objek tipe menggunakan fungsi Java.type() dalam javascript mirip dengan yang ada di java.
Misalnya, Anda dapat instantiate kelas menggunakan metode berikut:
var anarraylist = java.type baru ("java.util.arraylist");Objek tipe Java dapat digunakan untuk membuat instansiasi objek Java. Kode berikut menunjukkan cara instantiate objek baru menggunakan konstruktor default dan memanggil konstruktor yang berisi parameter:
var arraylist = java.type ("java.util.arraylist"); var defaultSizeArrayList = ArrayList baru; var customSizeArrayList = new arraylist (16); Anda dapat menggunakan metode Java.type() untuk mendapatkan jenis objek, dan Anda dapat menggunakan metode berikut untuk mengakses properti dan metode statis:
var file = java.type ("java.io.file"); file.createTempFile ("nashorn", ".tmp"); Jika Anda ingin mengakses kelas statis internal, Anda dapat melewati tanda dolar $ ke metode Java.type() .
Kode berikut menunjukkan cara mengembalikan kelas Float dalam java.awt.geom.Arc2D :
var float = java.type ("java.awt.geom.arc2d $ float");Jika Anda sudah memiliki objek tipe kelas eksternal, maka Anda dapat mengakses kelas dalamnya seperti Anda akan mengakses properti, seperti yang ditunjukkan di bawah ini:
var arc2d = java.type ("java.awt.geom.arc2d") var float = arc2d.floatKarena ini adalah kelas dalam non-statis, contoh kelas eksternal harus dilewatkan sebagai parameter untuk konstruktor.
Meskipun menggunakan objek tipe dalam JavaScript mirip dengan yang ada di java, itu masih agak berbeda dari objek java.lang.Class . Perbedaan ini adalah nilai pengembalian metode getClass() . Anda dapat menggunakan class dan properti static untuk mendapatkan informasi ini.
Kode berikut menunjukkan perbedaan antara keduanya:
var arraylist = java.type ("java.util.arraylist"); var a = arraylist baru; // Semua hal berikut adalah benar: cetak ("Tipe bertindak sebagai target dari instance dari:" + (instance dari aSrayList ("cetak (" cetak) tidak bertindak sebagai target instance dari: " +! (a instance a.get (" get ("cetak) (class tidak bertindak sebagai target dari instance:" +! (a.getClass ()! == ArrayList)); print ("properti` class` type adalah sama dengan getClass instance (): " + (a.getClass () === arrayList.class)); print (" Tipe sama dengan `static` koran));Sintaks dan Semantik, Ekspresi Kelas JavaScript dan Objek Runtime mirip dengan Java Semantik. Namun, di Java, objek kelas tidak memiliki properti bernama Static karena ekspresi kelas yang dikompilasi tidak digunakan sebagai objek.
2. Impor Paket dan Kelas Java
Untuk mengakses kelas Java berdasarkan nama sederhana, kami dapat menggunakan fungsi importPackage() dan importClass() untuk mengimpor paket dan kelas Java. Fungsi -fungsi ini ada dalam file skrip kompatibilitas (mozilla_compat.js).
Contoh berikut menunjukkan cara menggunakan fungsi importPackage() dan importClass() :
// Muat skrip kompatibilitas ("Nashorn: mozilla_compat.js"); // Impor packageMportPackage java.awt (java.awt); setVisible () methodframe.setVisible (true); // akses javabean propertyprint (frame.title); Paket Java dapat diakses melalui Paket Variabel Global, seperti Packages.java.util.Vector atau Packages.javax.swing.JFrame . Namun, paket Java SE standar memiliki metode akses yang lebih sederhana, seperti: Java sesuai dengan package.java, javax sesuai dengan package.javax, dan org sesuai dengan package.org.
Paket Java.lang tidak memerlukan impor secara default, karena ini akan bertentangan dengan objek bawaan JavaScript lainnya seperti Object , Boolean , dan Math . Selain itu, mengimpor paket dan kelas Java apa pun juga dapat menyebabkan konflik nama variabel di bawah ruang lingkup global JavaScript. Untuk menghindari konflik, kami mendefinisikan objek JavaMaMporter dan membatasi ruang lingkup paket dan kelas Java yang diimpor melalui pernyataan with , seperti yang ditunjukkan dalam kode berikut:
// Buat objek JavaMaMporter dengan paket dan kelas yang ditentukan untuk imporvar gui = javaimporter baru (java.awt, javax.swing); // lewati objek javaimporter ke pernyataan "dengan" dan mengakses kelas // dari paket yang diimpor dengan nama -nama sederhana mereka dalam body -body with with with with with with with) {var var = var = var awtframe = "var awtframe =" bingkai need (gui) {var var = "var awtframe = awtframe =" bingkai need; var jframe = jframe baru ("Swing JFrame");};3. Gunakan array java
Untuk membuat objek array Java, Anda pertama -tama harus mendapatkan objek tipe array Java dan menginisialisasi itu. Atribut sintaks dan length akses javascript ke elemen array sama dengan java, seperti yang ditunjukkan pada kode berikut:
var stringArray = java.type ("java.lang.string []"); var a = stringarray baru (5); // Atur nilai elemen pertama [0] = "Scripting sangat bagus!"; // Cetak panjang array (a.length); // cetak nilai elemen pertama (0]); Diberi array JavaScript, kami juga dapat mengubahnya menjadi array Java menggunakan metode Java.to() . Kita perlu meneruskan array JavaScript sebagai parameter ke metode dan menentukan jenis array yang akan dikembalikan, yang dapat berupa string atau objek tipe. Kita juga dapat mengabaikan parameter tipe objek untuk mengembalikan array objek []. Operasi konversi dilakukan sesuai dengan aturan konversi ecmascript. Kode berikut menunjukkan cara mengubah array JavaScript menjadi array Java melalui parameter Java.to() yang berbeda:
// Buat array javascript var anarray = [1, "13", false]; // Konversi array ke java int [] array var javaintarray = java.to (anarray, "int []"); print (javaintarray [0]); // mencetak nomor 1Print (JavaintArray [1]); // mencetak nomor 13print (JavaintArray [2]); // Cetak nomor 0 // Konversi array javascript ke javastringarray = java.to (anarray, java.type ("java.lang.string []")); print (javastringarray [0]); // cetak string "1" cetak (javastringarray [1]); // mencetak string "13" cetak (javastringarray [2]); // Cetak string "false" // konversi array javascript ke objek java [] array var javaobjectarray = java.to (anarray); print (javaobjectArray [0]); // mencetak nomor 1print (javaObjectArray [1]); // mencetak string "13" print (javaoBjectArray [2]); // mencetak nilai boolean "false" Anda dapat menggunakan metode Java.from() untuk mengubah array java menjadi array javascript.
Kode berikut menunjukkan cara mengonversi array yang berisi daftar file dalam direktori saat ini menjadi array JavaScript:
// Get the Java File type objectvar File = Java.type("java.io.File");// Create a Java array of File objectsvar listCurDir = new File(".").listFiles();// Convert the Java array to a JavaScript arrayvar jsList = Java.from(listCurDir);// Print the JavaScript arrayprint (jslist);Melihat:
Dalam kebanyakan kasus, Anda dapat menggunakan objek Java dalam skrip Anda tanpa mengubahnya menjadi objek JavaScript.
4. Menerapkan antarmuka java
Sintaks dari mengimplementasikan antarmuka Java di JavaScript mirip dengan metode mendefinisikan kelas anonim di Java. Kami hanya perlu membuat instantiasi antarmuka dan mengimplementasikan metodenya dengan fungsi JavaScript.
Kode berikut menunjukkan cara mengimplementasikan antarmuka Runnable :
// Buat objek yang mengimplementasikan antarmuka runnable dengan mengimplementasikan // metode run () sebagai javascript functionVar r = new java.lang.runnable () {run: function () {print ("running .../n"); }}; // Variabel R dapat diteruskan ke metode Java yang mengharapkan pengimpian objek // java.lang.runnable Interfacevar th = new java.lang.thread (r); th.start (); th.join (); Jika suatu metode menginginkan objek, objek ini mengimplementasikan antarmuka dengan hanya satu metode, Anda dapat meneruskan fungsi skrip ke metode ini alih -alih meneruskan objek. Misalnya, dalam contoh di atas, konstruktor Thread() memerlukan objek yang mengimplementasikan antarmuka Runnable sebagai parameter. Kita dapat memanfaatkan konversi otomatis untuk meneruskan fungsi skrip ke konstruktor Thread() .
Contoh berikut menunjukkan cara membuat objek Thread tanpa mengimplementasikan antarmuka Runnable :
// Tentukan fungsi fungsi fungsi fungsi javascript () {print ("I am func!");}; // Lewati fungsi JavaScript alih -alih objek yang mengimplementasikan // java.lang.runnable Interfacevar th = new java.lang.thread (funct); th.start (); th.jooin (); Anda dapat mengimplementasikan beberapa antarmuka dengan meneruskan objek tipe terkait ke fungsi Java.extend() .
5. Perpanjang kelas java abstrak
Anda dapat membuat instantiate subclass kelas abstrak anonim, cukup berikan objek JavaScript ke konstruktor, yang berisi beberapa properti yang sesuai dengan nilai yang diimplementasikan dengan metode kelas abstrak. Jika metode kelebihan beban, fungsi JavaScript akan memberikan implementasi semua varian metode. Contoh berikut menunjukkan cara menginisialisasi subclass dari Timertask kelas abstrak:
var timertask = java.type ("java.util.timertask"); var Task = new timertask ({run: function () {print ("hello world!")}}); Selain memanggil konstruktor dan parameter yang lewat, kami juga dapat memberikan parameter secara langsung setelah ekspresi new .
Contoh berikut menunjukkan cara menggunakan sintaks ini (mirip dengan definisi kelas internal anonim di java), yang sedikit lebih sederhana daripada contoh di atas:
var Task = new TimerSask {run: function () {print ("Hello World!")}};Jika kelas abstrak berisi metode abstrak tunggal (tipe SAM), maka kita tidak perlu meneruskan objek JavaScript ke konstruktor, kita dapat melewati antarmuka fungsi yang mengimplementasikan metode tersebut. Contoh berikut menunjukkan cara menggunakan tipe SAM untuk menyederhanakan kode:
var Task = new timerKask (function () {print ("Hello World!")});Terlepas dari sintaks yang Anda pilih, jika Anda perlu memanggil konstruktor yang berisi parameter, Anda dapat menentukan parameter dalam objek dan fungsi implementasi.
Jika Anda ingin memanggil metode Java yang membutuhkan parameter tipe SAM, Anda dapat meneruskan fungsi JavaScript ke metode tersebut. Nashorn akan membuat instantiasi subkelas sesuai dengan kebutuhan metode dan menggunakan fungsi ini untuk mengimplementasikan metode abstrak yang unik.
Kode berikut menunjukkan cara memanggil metode Timer.schedule() , yang membutuhkan objek TimerTask sebagai parameter:
var timer = java.type ("java.util.timer"); timer.schedule (function () {print ("Hello World!")});Melihat:
Sintaks sebelumnya mengasumsikan bahwa tipe SAM yang diperlukan adalah antarmuka atau berisi konstruktor default, yang digunakan Nashorn untuk menginisialisasi subclass. Ini tidak mungkin untuk menggunakan kelas yang tidak mengandung konstruktor default.
6. Perluas kelas Java tertentu
Untuk menghindari kebingungan, sintaks untuk memperluas kelas abstrak tidak dapat digunakan untuk memperluas kelas konkret. Karena kelas konkret dapat dipakai, sintaks semacam itu diuraikan ke dalam upaya untuk membuat instance kelas baru dan meneruskan objek kelas yang dibutuhkan oleh konstruktor (jika jenis objek yang diharapkan adalah antarmuka). Untuk menunjukkan masalah ini, silakan lihat kode sampel berikut:
var t = new java.lang.thread ({run: function () {print ("Thread Running!")}}); Baris kode ini diuraikan untuk memperpanjang kelas Thread dan mengimplementasikan metode run() , dan instantiasi kelas Thread diteruskan ke konstruktornya objek yang mengimplementasikan antarmuka yang dapat dijalankan.
Untuk memperluas kelas konkret, berikan objek tipe ke fungsi Java.extend() , dan kemudian mengembalikan objek jenisnya ke subkelasnya. Kemudian Anda dapat menggunakan objek tipe subkelas ini untuk membuat instance dan memberikan implementasi metode tambahan.
Kode berikut akan menunjukkan kepada Anda cara memperluas kelas Thread dan mengimplementasikan metode run() :
var thread = java.type ("java.lang.thread"); var threadextender = java.extend (thread); var t = new threadextender () {run: function () {print ("Thread running!")}}; Fungsi Java.extend() bisa mendapatkan daftar beberapa jenis objek. Anda dapat menentukan tidak lebih dari satu objek tipe Java, atau Anda dapat menentukan jumlah objek tipe sebanyak antarmuka Java. Objek tipe yang dikembalikan memperluas kelas yang ditentukan (atau java.lang.Object , jika tidak ada objek tipe yang ditentukan), kelas ini mengimplementasikan semua antarmuka. Objek tipe kelas tidak perlu berada di bagian atas daftar.
7. Metode untuk mengakses superclass (kelas induk)
Metode yang ingin mengakses kelas induk dapat menggunakan fungsi Java .super() .
Contoh berikut menunjukkan cara memperluas kelas java.lang.Exception dan mengakses metode kelas induk.
Contoh 3-1 Metode untuk mengakses kelas induk (super.js) var exception = java.type ("java.lang.exception"); var exceptionAdapter = java.extend (pengecualian); var exception = exceptionAdapter baru ("Pesan Pengecualian saya") {getMessage: function () {var _super saya; return _super_.getMessage (). Touppercase (); }} coba {throw exception;} catch (ex) {print (exception);}Jika Anda menjalankan kode di atas, Anda akan mencetak yang berikut:
jdk.nashorn.javaadapters.java.lang.Exception: Pesan Pengecualian Saya
8. mengikat untuk diimplementasikan ke kelas
Di bagian sebelumnya kami menjelaskan cara memperluas kelas Java dan mengimplementasikan antarmuka menggunakan parameter objek JavaScript tambahan. Implementasi terikat pada contoh tertentu, yang dibuat melalui baru, bukan seluruh kelas. Ada beberapa manfaat untuk melakukan ini, seperti jejak memori saat runtime, karena Nashorn dapat membuat adaptor universal tunggal untuk setiap kombinasi jenis implementasi.
Contoh berikut menunjukkan bahwa contoh yang berbeda dapat menjadi kelas Java yang sama, tetapi objek implementasi JavaScript mereka berbeda:
var Runnable = java.lang.Runnable;var r1 = new Runnable(function() { print("I'm runnable 1!") });var r2 = new Runnable(function() { print("I'm runnable 2!") });r1.run();r2.run();print("We share the same class: " + (r1.class === r2.class));Kode di atas akan mencetak hasil berikut:
Saya runnable 1! Saya runnable 2! Kami berbagi kelas yang sama: Benar
Jika Anda ingin meneruskan instance kelas ke API eksternal (seperti kerangka JavaFX, meneruskan instance aplikasi ke API JavaFX), Anda harus memperluas kelas Java atau mengimplementasikan antarmuka yang terikat ke kelas itu, daripada instance -nya. Anda dapat mengimplementasikan kelas dengan meneruskan pengikatan objek JavaScript dan meneruskannya ke parameter terakhir dari fungsi java.extend (). Ini menciptakan kelas baru dengan konstruktor yang sama dengan kelas asli, karena mereka tidak memerlukan implementasi tambahan parameter objek.
Contoh berikut menunjukkan bagaimana mengikat implementasi ke dalam kelas dan menunjukkan bahwa kelas implementasi berbeda untuk panggilan yang berbeda dalam kasus ini:
var runnableImpl1 = java.extend (java.lang.runnable, function () {print ("I'm runnable 1!")}); var runnableImpl2 = java.extend (java.lang.runnable, function () {print ("I'm runnable 2!")}; RunnableImpl2 (); r1.run (); r2.run (); print ("Kami berbagi kelas yang sama:" + (r1.class === r2.class));Contoh hasil eksekusi di atas adalah sebagai berikut:
Saya runnable 1! Saya runnable 2! Kami berbagi kelas yang sama: false
Memindahkan objek implementasi dari panggilan konstruktor ke panggilan fungsi Java.extend() menghindari parameter tambahan yang diperlukan dalam panggilan konstruktor. Setiap panggilan ke fungsi Java.extend() membutuhkan objek implementasi dari kelas yang ditentukan untuk menghasilkan kelas adaptor Java baru. Kelas adaptor yang diimplementasikan dengan batas kelas masih dapat menggunakan parameter konstruktor tambahan untuk lebih mengesampingkan perilaku contoh tertentu. Jadi Anda dapat menggabungkan kedua metode ini: Anda dapat memberikan bagian dari implementasi JavaScript di kelas dasar, kemudian meneruskannya ke fungsi Java.extend() , dan memberikan implementasi instance di objek dan meneruskannya ke konstruktor. Beberapa definisi fungsi objek akan ditimpa ketika objek didefinisikan dan diteruskan ke konstruktor.
Kode berikut menunjukkan cara menimpa fungsi objek batas kelas dengan meneruskan fungsi ke konstruktor:
var runnableImpl = java.extend (java.lang.runnable, function () {print ("I'm runnable 1!")}); var r1 = new runnableImpl (); var r2 = runnableImpl baru (function () {print ("I'm runnable 2!")}); r1.r1 (function () {cetak ("I'm runnable 2!")}); r1.r1 (function () {cetak ("I'm runnable 2!")}); r1.r1 (function () {cetak ("I'm runnable 2!")}); r1. (r1.class === r2.class));Hasil pencetakan setelah contoh di atas dijalankan adalah sebagai berikut:
Saya runnable 1! Saya runnable 2! Kami berbagi kelas yang sama: Benar
9. Pilih Varian Overload Metode
Metode Java dapat kelebihan beban dengan menggunakan jenis parameter yang berbeda. Java Compiler (Javac) akan memilih metode yang benar untuk dieksekusi pada waktu kompilasi. Parsing metode kelebihan java di Nashorn dieksekusi ketika metode ini dipanggil. Ini juga merupakan cara untuk menentukan metode yang benar berdasarkan jenis parameter. Tetapi jika jenis parameter aktual akan menyebabkan ambiguitas, kami dapat secara eksplisit menentukan varian yang kelebihan beban tertentu. Ini meningkatkan kinerja eksekusi program, karena mesin Nashorn tidak perlu membedakan metode mana yang akan dihubungi selama panggilan.
Varian yang kelebihan beban diekspos sebagai properti khusus. Kita dapat merujuknya dalam bentuk string, yang berisi nama metode dan tipe parameter, dan dikelilingi oleh tanda kurung.
Contoh berikut menunjukkan cara memanggil metode System.out.println() dengan varian parameter Object , kami meneruskan string "halo" untuk itu:
var out = java.lang.system.out; out ["println (objek)"] ("hello");Dalam contoh di atas, menggunakan nama kelas objek saja sudah cukup karena itu adalah tanda tangan yang secara unik mengidentifikasi yang benar. Kasing di mana Anda harus menggunakan nama kelas penuh adalah bahwa dua fungsi varian yang kelebihan beban menggunakan jenis parameter yang berbeda, tetapi jenisnya memiliki nama yang sama (ini dimungkinkan, misalnya, paket yang berbeda berisi nama kelas yang sama).
10. Pemetaan Jenis Data
Sebagian besar konversi Java dan JavaScript sebelumnya berfungsi dengan baik seperti yang Anda harapkan. Dalam bab -bab sebelumnya, kami menyebutkan beberapa pemetaan tipe data sederhana antara Java dan JavaScript. Misalnya, data tipe array dapat dikonversi secara eksplisit, fungsi JavaScript dapat secara otomatis dikonversi menjadi tipe SAM ketika dilewatkan sebagai parameter ke metode Java. Setiap objek JavaScript mengimplementasikan antarmuka java.util.Map untuk memungkinkan API menerima pemetaan secara langsung. Saat memberikan nilai ke Java API, mereka akan dikonversi ke tipe numerik target yang diharapkan, yang dapat berupa tipe enkapsulasi atau tipe data primitif. Jika tipe target tidak terlalu pasti (seperti angka), Anda hanya dapat mengharuskannya untuk menjadi tipe angka, dan kemudian secara khusus merangkum tipe, seperti double, integer, long, dll. Optimalisasi internal membuat nilai numerik dari jenis paket apa pun. Kolega, Anda dapat memberikan nilai JavaScript apa pun ke Java API, apakah itu tipe yang dienkapsulasi atau tipe primitif, karena algoritma konversi ToNumber JavaScript akan secara otomatis memproses nilainya. Jika metode Java memerlukan parameter objek String atau Boolean , JavaScript akan menggunakan transformasi ToString dan ToBoolean untuk mendapatkan nilainya.
Melihat:
Karena pertimbangan optimasi kinerja internal untuk operasi string, string JavaScript tidak selalu sesuai dengan tipe java.lang.string, atau mereka juga mungkin tipe java.lang.CharSequence . Jika Anda meneruskan string JavaScript ke metode Java yang memerlukan parameter java.lang.String , maka string CharSequence adalah tipe java.lang.String , tetapi jika tanda tangan metode Anda ingin lebih umum (misalnya, tipe parameter yang diterima adalah java.langar
Meringkaskan
Di atas adalah seluruh konten artikel ini. Saya berharap ini akan membantu untuk belajar dan bekerja semua orang. Jika Anda memiliki pertanyaan, Anda dapat meninggalkan pesan untuk berkomunikasi.