本文中所有的代码使用 JavaScript 编写,但你也可以用其他兼容 JSR 223 的脚本语言。这些例子可作为脚本文件也可以在交互式 Shell 中一次运行一个语句的方式来运行。在 JavaScript 中访问对象的属性和方法的语法与 Java 语言相同。
本文包含如下几部分:
1、访问 Java 类
为了在 JavaScript 中访问原生类型或者引用 Java 类型,可以调用 Java.type() 函数,该函数根据传入的完整类名返回对应对象的类型。下面代码显示如何获取不同的对象类型:
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() 函数返回的类型对象的方法跟在 Java 的类似。
例如你可以使用如下方法来实例化一个类:
var anArrayList = new Java.type("java.util.ArrayList");
Java 类型对象可用来实例化 Java 对象。下面的代码显示如何使用默认的构造函数实例化一个新对象以及调用包含参数的构造函数:
var ArrayList = Java.type("java.util.ArrayList"); var defaultSizeArrayList = new ArrayList; var customSizeArrayList = new ArrayList(16);
你可以使用 Java.type() 方法来获取对象类型,可以使用如下方法来访问静态属性以及方法:
var File = Java.type("java.io.File"); File.createTempFile("nashorn", ".tmp");
如果要访问内部静态类,可以传递美元符号 $ 给 Java.type() 方法。
下面代码显示如何返回 java.awt.geom.Arc2D 的 Float 内部类:
var Float = Java.type("java.awt.geom.Arc2D$Float");
如果你已经有一个外部类类型对象,那么你可以像访问属性一样访问其内部类,如下所示:
var Arc2D = Java.type("java.awt.geom.Arc2D") var Float = Arc2D.Float
由于是非静态内部类,必须传递的是外部类实例作为参数给构造函数。
虽然在 JavaScript 中使用类型对象跟在 Java 中类似,但其与 java.lang.Class 对象还是有些区别的,这个区别就是 getClass() 方法的返回值。你可以使用 class 和 static 属性来获取这个信息。
下面代码显示二者的区别:
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 在编译时类表达式和运行时对象都和 Java 语义类似。不过在 Java 中 Class 对象是没有名为 static 这样的属性,因为编译时的类表达式不作为对象。
2、导入 Java 包和类
为了根据其简单的名称来访问 Java 类,我们可以使用 importPackage() 和 importClass() 函数来导入 Java 的包和类。这些函数存在于兼容性脚本文件 (mozilla_compat.js) 中。
下面例子展示如何使用 importPackage() 和 importClass() 函数:
// Load compatibility script load("nashorn:mozilla_compat.js"); // Import the java.awt package importPackage(java.awt); // Import the java.awt.Frame class importClass(java.awt.Frame); // Create a new Frame object var frame = new java.awt.Frame("hello"); // Call the setVisible() method frame.setVisible(true); // Access a JavaBean property print(frame.title);
可以通过 Packages 全局变量来访问 Java 包,例如Packages.java.util.Vector 或者 Packages.javax.swing.JFrame。但标准的 Java SE 包有更简单的访问方式,如: java 对应 Packages.java, javax 对应 Packages.javax, 以及 org 对应 Packages.org。
java.lang 包默认不需要导入,因为这会和 Object、Boolean、Math 等其他 JavaScript 内建的对象在命名上冲突。此外,导入任何 Java 包和类也可能导致 JavaScript 全局作用域下的变量名冲突。为了避免冲突,我们定义了一个 JavaImporter 对象,并通过 with 语句来限制导入的 Java 包和类的作用域,如下列代码所示:
// Create a JavaImporter object with specified packages and classes to import var 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 body with (Gui) { var awtframe = new Frame("AWT Frame"); var jframe = new JFrame("Swing JFrame"); };
3、使用 Java 数组