在JavaScript中调用Java类和接口的方法(3)

如果你想要调用一个要求 SAM 类型参数的 Java 方法,你可以传递一个 JavaScript 函数给该方法。Nashorn 将根据方法需要来实例化一个子类并使用这个函数去实现唯一的抽象方法。

下面的代码显示如何调用 Timer.schedule() 方法,该方法要求一个 TimerTask 对象作为参数:

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

注意:

前面的语法假设所要求的 SAM 类型是一个接口或者包含一个默认构造函数,Nashorn 用它来初始化一个子类。这里是无法使用不包含默认构造函数的类的。

6、扩展具体 Java 类

为了避免混淆,扩展抽象类的语法不能用于扩展具体类。因为一个具体类是可以被实例化的,这样的语法会被解析成试图创建一个新的类实例并传递构造函数所需类的对象(如果预期的对象类型是一个接口)。为了演示这个问题,请看看下面的示例代码:

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

这行代码被解析为扩展了 Thread 类并实现了 run() 方法,而 Thread 类的实例化是通过传递给其构造函数一个实现了 Runnable 接口的对象。

为了扩展一个具体类,传递其类型对象给 Java.extend() 函数,然后返回其子类的类型对象。紧接着就可以使用这个子类的类型对象来创建实例并提供额外的方法实现。

下面的代码将向你展示如何扩展 Thread 类并实现 run() 方法:

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

Java.extend() 函数可以获取多个类型对象的列表。你可以指定不超过一个 Java 的类型对象,也可以指定跟 Java接口一样多的类型对象数量。返回的类型对象扩展了指定的类(或者是 java.lang.Object ,如果没有指定类型对象的话),这个类实现了所有的接口。类的类型对象无需在列表中排在首位。

7、访问超类(父类)的方法

想要访问父类的方法可以使用 Java .super() 函数。

下面的例子中显示如何扩展 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); }

如果你运行上面代码将会打印如下内容:

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

8、绑定实现到类

前面的部分我们描述了如何扩展 Java 类以及使用一个额外的 JavaScript 对象参数来实现接口。实现是绑定的具体某个实例上的,这个实例是通过 new 来创建的,而不是整个类。这样做有一些好处,例如运行时的内存占用,因为 Nashorn 可以为每个实现的类型组合创建一个单一的通用适配器。

下面的例子展示不同的实例可以是同一个 Java 类,而其 JavaScript 实现对象却是不同的:

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

上述代码将打印如下结果:

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

如果你想传递类的实例给外部 API(如 JavaFX 框架,传递 Application 实例给 JavaFX API),你必须扩展一个 Java 类或者实现了与该类绑定的接口,而不是它的实例。你可以通过传递一个 JavaScript 对象绑定实现类并传递给 Java.extend() 函数的最后一个参数。这个会创建一个跟原有类包含一样构造函数的新类,因为它们不需要额外实现对象参数。

下面的例子展示如何绑定实现到类中,并演示在这种情况下对于不同调用的实现类是不同的:

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

上面例子执行结果如下:

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

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wzfwwg.html