国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > JavaScript > 正文

在JavaScript中調(diào)用Java類和接口的方法

2019-11-20 09:03:15
字體:
供稿:網(wǎng)友

前言

本文中所有的代碼使用 JavaScript 編寫,但你也可以用其他兼容 JSR 223 的腳本語言。這些例子可作為腳本文件也可以在交互式 Shell 中一次運(yùn)行一個(gè)語句的方式來運(yùn)行。在 JavaScript 中訪問對象的屬性和方法的語法與 Java 語言相同。

本文包含如下幾部分:

1、訪問 Java 類

為了在 JavaScript 中訪問原生類型或者引用 Java 類型,可以調(diào)用 Java.type() 函數(shù),該函數(shù)根據(jù)傳入的完整類名返回對應(yīng)對象的類型。下面代碼顯示如何獲取不同的對象類型:

var ArrayList = Java.type("java.util.ArrayList");var intType = Java.type("int");var StringArrayType = Java.type("java.lang.String[]");var int2DArrayType = Java.type("int[][]");

在 JavaScript 中使用 Java.type() 函數(shù)返回的類型對象的方法跟在 Java 的類似。

例如你可以使用如下方法來實(shí)例化一個(gè)類:

var anArrayList = new Java.type("java.util.ArrayList");

Java 類型對象可用來實(shí)例化 Java 對象。下面的代碼顯示如何使用默認(rèn)的構(gòu)造函數(shù)實(shí)例化一個(gè)新對象以及調(diào)用包含參數(shù)的構(gòu)造函數(shù):

var ArrayList = Java.type("java.util.ArrayList");var defaultSizeArrayList = new ArrayList;var customSizeArrayList = new ArrayList(16);

你可以使用 Java.type() 方法來獲取對象類型,可以使用如下方法來訪問靜態(tài)屬性以及方法:

var File = Java.type("java.io.File");File.createTempFile("nashorn", ".tmp");

如果要訪問內(nèi)部靜態(tài)類,可以傳遞美元符號 $ 給 Java.type() 方法。

下面代碼顯示如何返回 java.awt.geom.Arc2DFloat 內(nèi)部類:

var Float = Java.type("java.awt.geom.Arc2D$Float");

如果你已經(jīng)有一個(gè)外部類類型對象,那么你可以像訪問屬性一樣訪問其內(nèi)部類,如下所示:

var Arc2D = Java.type("java.awt.geom.Arc2D")var Float = Arc2D.Float

由于是非靜態(tài)內(nèi)部類,必須傳遞的是外部類實(shí)例作為參數(shù)給構(gòu)造函數(shù)。

雖然在 JavaScript 中使用類型對象跟在 Java 中類似,但其與 java.lang.Class 對象還是有些區(qū)別的,這個(gè)區(qū)別就是 getClass() 方法的返回值。你可以使用 class static 屬性來獲取這個(gè)信息。

下面代碼顯示二者的區(qū)別:

var ArrayList = Java.type("java.util.ArrayList");var a = new ArrayList;// All of the following are true:print("Type acts as target of instanceof: " + (a instanceof ArrayList));print("Class doesn't act as target of instanceof: " + !(a instanceof a.getClass()));print("Type is not the same as instance's getClass(): " + (a.getClass() !== ArrayList));print("Type's `class` property is the same as instance's getClass(): " + (a.getClass() === ArrayList.class));print("Type is the same as the `static` property of the instance's getClass(): " + (a.getClass().static === ArrayList));

在語法和語義上,JavaScript 在編譯時(shí)類表達(dá)式和運(yùn)行時(shí)對象都和 Java 語義類似。不過在 Java 中 Class 對象是沒有名為 static 這樣的屬性,因?yàn)榫幾g時(shí)的類表達(dá)式不作為對象。

2、導(dǎo)入 Java 包和類

為了根據(jù)其簡單的名稱來訪問 Java 類,我們可以使用 importPackage() importClass() 函數(shù)來導(dǎo)入 Java 的包和類。這些函數(shù)存在于兼容性腳本文件 (mozilla_compat.js) 中。

下面例子展示如何使用 importPackage() importClass() 函數(shù):

// Load compatibility scriptload("nashorn:mozilla_compat.js");// Import the java.awt packageimportPackage(java.awt);// Import the java.awt.Frame classimportClass(java.awt.Frame);// Create a new Frame objectvar frame = new java.awt.Frame("hello");// Call the setVisible() methodframe.setVisible(true);// Access a JavaBean propertyprint(frame.title);

可以通過 Packages 全局變量來訪問 Java 包,例如Packages.java.util.Vector 或者 Packages.javax.swing.JFrame。但標(biāo)準(zhǔn)的 Java SE 包有更簡單的訪問方式,如: java 對應(yīng) Packages.java, javax 對應(yīng) Packages.javax, 以及 org 對應(yīng) Packages.org。

java.lang 包默認(rèn)不需要導(dǎo)入,因?yàn)檫@會和 ObjectBooleanMath 等其他 JavaScript 內(nèi)建的對象在命名上沖突。此外,導(dǎo)入任何 Java 包和類也可能導(dǎo)致 JavaScript 全局作用域下的變量名沖突。為了避免沖突,我們定義了一個(gè) JavaImporter 對象,并通過 with 語句來限制導(dǎo)入的 Java 包和類的作用域,如下列代碼所示:

// Create a JavaImporter object with specified packages and classes to importvar Gui = new JavaImporter(java.awt, javax.swing);// Pass the JavaImporter object to the "with" statement and access the classes// from the imported packages by their simple names within the statement's bodywith (Gui) { var awtframe = new Frame("AWT Frame"); var jframe = new JFrame("Swing JFrame");};

3、使用 Java 數(shù)組

為了創(chuàng)建 Java 數(shù)組對象,首先需要獲取 Java 數(shù)組類型對象并進(jìn)行初始化。JavaScript 訪問數(shù)組元素的語法以及 length 屬性都跟 Java 一樣,如下列代碼所示:

var StringArray = Java.type("java.lang.String[]");var a = new StringArray(5);// Set the value of the first elementa[0] = "Scripting is great!";// Print the length of the arrayprint(a.length);// Print the value of the first elementprint(a[0]);

給定一個(gè) JavaScript 數(shù)組 我們還可以用 Java.to() 方法將它轉(zhuǎn)成 Java 數(shù)組。我們需要將 JavaScript 數(shù)組作為參數(shù)傳給該方法,并指定要返回的數(shù)組類型,可以是一個(gè)字符串,或者是類型對象。我們也可以忽略類型對象參數(shù)來返回 Object[] 數(shù)組。轉(zhuǎn)換操作是根據(jù) ECMAScript 轉(zhuǎn)換規(guī)則進(jìn)行的。下面代碼展示如何通過不同的 Java.to() 的參數(shù)將 JavaScript 數(shù)組變成 Java 數(shù)組:

// 創(chuàng)建一個(gè) JavaScript 數(shù)組var anArray = [1, "13", false];// 將數(shù)組轉(zhuǎn)換成 java 的 int[] 數(shù)組var javaIntArray = Java.to(anArray, "int[]");print(javaIntArray[0]); // prints the number 1print(javaIntArray[1]); // prints the number 13print(javaIntArray[2]); // prints the number 0// 將 JavaScript 數(shù)組轉(zhuǎn)換成 Java 的 String[] 數(shù)組var javaStringArray = Java.to(anArray, Java.type("java.lang.String[]"));print(javaStringArray[0]); // prints the string "1"print(javaStringArray[1]); // prints the string "13"print(javaStringArray[2]); // prints the string "false"http:// 將 JavaScript 數(shù)組轉(zhuǎn)換成 Java 的 Object[] 數(shù)組var javaObjectArray = Java.to(anArray);print(javaObjectArray[0]); // prints the number 1print(javaObjectArray[1]); // prints the string "13"print(javaObjectArray[2]); // prints the boolean value "false"

你可以使用 Java.from() 方法來將一個(gè) Java 數(shù)組轉(zhuǎn)成 JavaScript 數(shù)組。

下面代碼演示如何將一個(gè)包含當(dāng)前目錄下文件列表的數(shù)組轉(zhuǎn)成 JavaScript 數(shù)組:

// 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);

注意:

大多數(shù)情況下,你可以在腳本中使用 Java 對象而無需轉(zhuǎn)換成 JavaScript 對象。

4、實(shí)現(xiàn) Java 接口

在 JavaScript 實(shí)現(xiàn) Java 接口的語法與在 Java 總定義匿名類的方法類似。我們只需要實(shí)例化接口并用 JavaScript 函數(shù)實(shí)現(xiàn)其方法即可。

下面代碼演示如何實(shí)現(xiàn) Runnable 接口:

// Create an object that implements the Runnable interface by implementing// the run() method as a JavaScript functionvar r = new java.lang.Runnable() { run: function() {  print("running.../n"); }};// The r variable can be passed to Java methods that expect an object implementing// the java.lang.Runnable interfacevar th = new java.lang.Thread(r);th.start();th.join();

如果一個(gè)方法希望一個(gè)對象,這個(gè)對象實(shí)現(xiàn)了只有一個(gè)方法的接口,你可以傳遞一個(gè)腳本函數(shù)給這個(gè)方法,而不是傳遞對象。例如,在上面的例子中 Thread() 構(gòu)造函數(shù)要求一個(gè)實(shí)現(xiàn)了 Runnable 接口的對象作為參數(shù)。我們可以利用自動轉(zhuǎn)換的優(yōu)勢傳遞一個(gè)腳本函數(shù)給 Thread() 構(gòu)造器。

下面的例子展示如何創(chuàng)建一個(gè) Thread 對象而無需實(shí)現(xiàn) Runnable 接口:

// Define a JavaScript functionfunction func() { print("I am func!");};// Pass the JavaScript function instead of an object that implements// the java.lang.Runnable interfacevar th = new java.lang.Thread(func);th.start();th.join();

你可以通過傳遞相關(guān)類型對象給 Java.extend() 函數(shù)來實(shí)現(xiàn)多個(gè)接口。

5、擴(kuò)展抽象 Java 類

你可以實(shí)例化一個(gè)匿名的抽象類的子類,只需要給構(gòu)造函數(shù)傳遞一個(gè) JavaScript 對象,對象中包含了一些屬性對應(yīng)了抽象類方法實(shí)現(xiàn)的值。如果一個(gè)方法是重載的,JavaScript 函數(shù)將會提供所有方法變種的實(shí)現(xiàn)。下面例子顯示如何初始化抽象類 TimerTask 的子類:

var TimerTask = Java.type("java.util.TimerTask");var task = new TimerTask({ run: function() { print("Hello World!") } });

除了調(diào)用構(gòu)造函數(shù)并傳遞參數(shù),我們還可以在 new 表達(dá)式后面直接提供參數(shù)。

下面的例子顯示該語法的使用方法(類似 Java 匿名內(nèi)部類的定義),這比上面的例子要簡單一些:

var task = new TimerTask { run: function() {  print("Hello World!") }};

如果抽象類包含單個(gè)抽象方法(SAM 類型),那么我們就無需傳遞 JavaScript 對象給構(gòu)造函數(shù),我們可以傳遞一個(gè)實(shí)現(xiàn)了該方法的函數(shù)接口。下面的例子顯示如何使用 SAM 類型來簡化代碼:

var task = new TimerTask(function() { print("Hello World!") });

不管你選擇哪種語法,如果你需要調(diào)用一個(gè)包含參數(shù)的構(gòu)造函數(shù),你可以在實(shí)現(xiàn)對象和函數(shù)中指定參數(shù)。

如果你想要調(diào)用一個(gè)要求 SAM 類型參數(shù)的 Java 方法,你可以傳遞一個(gè) JavaScript 函數(shù)給該方法。Nashorn 將根據(jù)方法需要來實(shí)例化一個(gè)子類并使用這個(gè)函數(shù)去實(shí)現(xiàn)唯一的抽象方法。

下面的代碼顯示如何調(diào)用 Timer.schedule() 方法,該方法要求一個(gè) TimerTask 對象作為參數(shù):

var Timer = Java.type("java.util.Timer");Timer.schedule(function() { print("Hello World!") });

注意:

前面的語法假設(shè)所要求的 SAM 類型是一個(gè)接口或者包含一個(gè)默認(rèn)構(gòu)造函數(shù),Nashorn 用它來初始化一個(gè)子類。這里是無法使用不包含默認(rèn)構(gòu)造函數(shù)的類的。

6、擴(kuò)展具體 Java 類

為了避免混淆,擴(kuò)展抽象類的語法不能用于擴(kuò)展具體類。因?yàn)橐粋€(gè)具體類是可以被實(shí)例化的,這樣的語法會被解析成試圖創(chuàng)建一個(gè)新的類實(shí)例并傳遞構(gòu)造函數(shù)所需類的對象(如果預(yù)期的對象類型是一個(gè)接口)。為了演示這個(gè)問題,請看看下面的示例代碼:

var t = new java.lang.Thread({ run: function() { print("Thread running!") } });

這行代碼被解析為擴(kuò)展了 Thread 類并實(shí)現(xiàn)了 run() 方法,而 Thread 類的實(shí)例化是通過傳遞給其構(gòu)造函數(shù)一個(gè)實(shí)現(xiàn)了 Runnable 接口的對象。

為了擴(kuò)展一個(gè)具體類,傳遞其類型對象給 Java.extend() 函數(shù),然后返回其子類的類型對象。緊接著就可以使用這個(gè)子類的類型對象來創(chuàng)建實(shí)例并提供額外的方法實(shí)現(xiàn)。

下面的代碼將向你展示如何擴(kuò)展 Thread 類并實(shí)現(xiàn) run() 方法:

var Thread = Java.type("java.lang.Thread");var threadExtender = Java.extend(Thread);var t = new threadExtender() { run: function() { print("Thread running!") }};

Java.extend() 函數(shù)可以獲取多個(gè)類型對象的列表。你可以指定不超過一個(gè) Java 的類型對象,也可以指定跟 Java接口一樣多的類型對象數(shù)量。返回的類型對象擴(kuò)展了指定的類(或者是 java.lang.Object ,如果沒有指定類型對象的話),這個(gè)類實(shí)現(xiàn)了所有的接口。類的類型對象無需在列表中排在首位。

7、訪問超類(父類)的方法

想要訪問父類的方法可以使用 Java .super() 函數(shù)。

下面的例子中顯示如何擴(kuò)展 java.lang.Exception 類,并訪問父類的方法。

Example 3-1 訪問父類的方法 (super.js)var Exception = Java.type("java.lang.Exception");var ExceptionAdapter = Java.extend(Exception);var exception = new ExceptionAdapter("My Exception Message") { getMessage: function() {  var _super_ = Java.super(exception);  return _super_.getMessage().toUpperCase(); }}try { throw exception;} catch (ex) { print(exception);}

如果你運(yùn)行上面代碼將會打印如下內(nèi)容:

jdk.nashorn.javaadapters.java.lang.Exception: MY EXCEPTION MESSAGE

8、綁定實(shí)現(xiàn)到類

前面的部分我們描述了如何擴(kuò)展 Java 類以及使用一個(gè)額外的 JavaScript 對象參數(shù)來實(shí)現(xiàn)接口。實(shí)現(xiàn)是綁定的具體某個(gè)實(shí)例上的,這個(gè)實(shí)例是通過 new 來創(chuàng)建的,而不是整個(gè)類。這樣做有一些好處,例如運(yùn)行時(shí)的內(nèi)存占用,因?yàn)?Nashorn 可以為每個(gè)實(shí)現(xiàn)的類型組合創(chuàng)建一個(gè)單一的通用適配器。

下面的例子展示不同的實(shí)例可以是同一個(gè) Java 類,而其 JavaScript 實(shí)現(xiàn)對象卻是不同的:

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));

上述代碼將打印如下結(jié)果:

I'm runnable 1!I'm runnable 2!We share the same class: true

如果你想傳遞類的實(shí)例給外部 API(如 JavaFX 框架,傳遞 Application 實(shí)例給 JavaFX API),你必須擴(kuò)展一個(gè) Java 類或者實(shí)現(xiàn)了與該類綁定的接口,而不是它的實(shí)例。你可以通過傳遞一個(gè) JavaScript 對象綁定實(shí)現(xiàn)類并傳遞給 Java.extend() 函數(shù)的最后一個(gè)參數(shù)。這個(gè)會創(chuàng)建一個(gè)跟原有類包含一樣構(gòu)造函數(shù)的新類,因?yàn)樗鼈儾恍枰~外實(shí)現(xiàn)對象參數(shù)。

下面的例子展示如何綁定實(shí)現(xiàn)到類中,并演示在這種情況下對于不同調(diào)用的實(shí)現(xiàn)類是不同的:

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!") });var r1 = new RunnableImpl1();var r2 = new RunnableImpl2();r1.run();r2.run();print("We share the same class: " + (r1.class === r2.class));

上面例子執(zhí)行結(jié)果如下:

I'm runnable 1!I'm runnable 2!We share the same class: false

將實(shí)現(xiàn)對象從構(gòu)造函數(shù)調(diào)用移到 Java.extend() 函數(shù)調(diào)用可以避免在構(gòu)造函數(shù)調(diào)用中所需的額外參數(shù)。每一個(gè) Java.extend() 函數(shù)的調(diào)用都需要一個(gè)指定類的實(shí)現(xiàn)對象生成一個(gè)新的 Java 適配器類。帶類邊界實(shí)現(xiàn)的適配器類仍可以使用一個(gè)額外的構(gòu)造參數(shù)用來進(jìn)一步重寫特定實(shí)例的行為。因此你可以合并這兩種方法:你可以在一個(gè)基礎(chǔ)類中提供部分 JavaScript 實(shí)現(xiàn),然后傳遞給 Java.extend() 函數(shù),以及在對象中提供實(shí)例實(shí)現(xiàn)并傳遞給構(gòu)造函數(shù)。對象定義的函數(shù)并傳遞給構(gòu)造函數(shù)時(shí)將覆蓋對象的一些函數(shù)定義。

下面的代碼演示如何通過給構(gòu)造函數(shù)傳遞一個(gè)函數(shù)來覆蓋類邊界對象的函數(shù):

var RunnableImpl = Java.extend(java.lang.Runnable, function() { print("I'm runnable 1!") });var r1 = new RunnableImpl();var r2 = new RunnableImpl(function() { print("I'm runnable 2!") });r1.run();r2.run();print("We share the same class: " + (r1.class === r2.class));

上面例子執(zhí)行后打印結(jié)果如下:

I'm runnable 1!I'm runnable 2!We share the same class: true

9、選擇方法重載變體

Java 的方法可以通過使用不同的參數(shù)類型進(jìn)行重載。Java 編譯器 (javac) 會在編譯時(shí)選擇正確的方法來執(zhí)行。在 Nashorn 中對Java 重載方法的解析實(shí)在方法被調(diào)用的時(shí)候執(zhí)行的。也是根據(jù)參數(shù)類型來確定正確的方法。但如果實(shí)際的參數(shù)類型會導(dǎo)致模棱兩可的情況下,我們可以顯式的指定具體某個(gè)重載變體。這會提升程序執(zhí)行的性能,因?yàn)?Nashorn 引擎無需在調(diào)用過程中去辨別該調(diào)用哪個(gè)方法。

重載的變種作為特別的屬性暴露出來。我們可以用字符串的形式來引用它們,字符串包含方法名稱、參數(shù)類型,兩者使用圓括號包圍起來。

下面的例子顯示如何調(diào)用  System.out.println() 方法帶 Object 參數(shù)的變種,我們傳遞一個(gè) “hello” 字符串給它:

var out = java.lang.System.out;out["println(Object)"]("hello");

上述的例子中,光使用 Object 類名就足夠了,因?yàn)樗俏ㄒ粯?biāo)識正確的簽名。你必須使用完整的類名的情況是兩個(gè)重載變種函數(shù)使用不同的參數(shù)類型,但是類型的名稱相同(這是可能的,例如不同包中包含相同的類名)。

10、映射數(shù)據(jù)類型

絕大多數(shù) Java 和 JavaScript 之前的轉(zhuǎn)換如你所期待的運(yùn)行良好。前面的章節(jié)中我們提到過一些簡單的 Java 和 JavaScript 之間的數(shù)據(jù)類型映射。例如可以顯式地轉(zhuǎn)換數(shù)組類型數(shù)據(jù),JavaScript 函數(shù)可以在當(dāng)成參數(shù)傳遞給 Java 方法時(shí)自動轉(zhuǎn)換成 SAM 類型。每個(gè) JavaScript 對象實(shí)現(xiàn)了 java.util.Map 接口來讓 API 可以直接接受映射。當(dāng)傳遞數(shù)值給 Java API 時(shí),會被轉(zhuǎn)成所期待的目標(biāo)數(shù)值類型,可以是封裝類型或者是原始數(shù)據(jù)類型。如果目標(biāo)類型不太確定(如 Number),你只能要求它必須是 Number 類型,然后專門針對該類型是封裝了 Double、Integer 或者是 Long 等等。內(nèi)部的優(yōu)化使得數(shù)值可以是任何封裝類型。同事你可以傳遞任意 JavaScript 值給 Java API,不管是封裝類型還是原始類型,因?yàn)?JavaScript 的 ToNumber 轉(zhuǎn)換算法將會自動處理其值。如果 Java 方法要求一個(gè) String 或者 Boolean 對象參數(shù),JavaScript 將會使用 ToString ToBoolean 轉(zhuǎn)換來獲得其值。

注意:

因?yàn)閷ψ址僮鞯膬?nèi)部性能優(yōu)化考慮,JavaScript 字符串并不總是對應(yīng) java.lang.String 類型,也可能是 java.lang.CharSequence 類型。如果你傳遞一個(gè) JavaScript 字符串給要求 java.lang.String 參數(shù)的 Java 方法,那么這個(gè) JavaScript 字符串就是 java.lang.String 類型,但如果你的方法簽名想要更加泛型化(例如接受的參數(shù)類型是 java.lang.Object),那么你得到的參數(shù)對象就會使一個(gè)實(shí)現(xiàn)了 CharSequence 類的對象,而不是一個(gè) Java 字符串對象。

總結(jié)
以上就是這篇文章的全部內(nèi)容,希望對大家的學(xué)習(xí)和工作能有一定的幫助,如果有疑問大家可以留言交流。

發(fā)表評論 共有條評論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 正安县| 东乡族自治县| 北京市| 阿拉尔市| 扶绥县| 岢岚县| 和顺县| 平湖市| 扎鲁特旗| 宁波市| 全椒县| 顺义区| 准格尔旗| 汤原县| 吉木乃县| 大英县| 博野县| 宁明县| 安岳县| 博乐市| 吴江市| 界首市| 敦化市| 那曲县| 巴里| 郓城县| 怀仁县| 金湖县| 康平县| 涞源县| 田东县| 北宁市| 阿坝县| 图们市| 尼勒克县| 开江县| 渝北区| 东乌珠穆沁旗| 河间市| 瑞昌市| 玉溪市|