Skip to content

7.4 使用Java对象

在脚本中平台支持使用Java对象来进行操作,以下文档向您展示如何实现与 Java 的互操作性以及可能的 JavaScript 到 Java 嵌入场景。

7.4.1 类访问

访问Java类,脚本引擎支持使用Java.type(typeName)来使用:

js
var FileClass = Java.type('java.io.File');

注意:默认情况下,Java类不会自动映射到全局变量,需要重写以使用该Java.type(name)函数

7.4.2 构造Java对象

构造一个Java对象可以用JavaScript的关键字构造:

js
var FileClass = Java.type('java.io.File');
var file = new FileClass("myFile.md");

7.4.3 字段和方法访问

Java 类的静态字段或 Java 对象的字段可以像 JavaScript 属性一样进行访问:

js
var JavaPI = Java.type('java.lang.Math').PI;

Java 方法可以像 JavaScript 函数一样被调用:

js
var file = new (Java.type('java.io.File'))("test.md");
var fileName = file.getName();

7.4.4 方法参数的转换

调用 Java 方法时,可能需要进行值转换。当 Java 方法需要一个long参数,并且int由脚本引擎提供时,就会发生这种情况。如果此转换导致有损转换,TypeError则会抛出:

java
//Java
void longArg   (long arg1);
void doubleArg (double arg2);
void intArg    (int arg3);
js
//JavaScript
javaObject.longArg(1);     //widening, OK
javaObject.doubleArg(1);   //widening, OK
javaObject.intArg(1);      //match, OK

javaObject.longArg(1.1);   //lossy conversion, TypeError!
javaObject.doubleArg(1.1); //match, OK
javaObject.intArg(1.1);    //lossy conversion, TypeError!

7.4.5 选择方法

Java中的方法重载是指可以定义多个同名方法,但它们的参数类型或个数不同。这样,在调用这些方法时,编译器会根据传入的参数来选择最合适的方法执行。比如说,有几个foo方法,分别接受不同类型的参数(比如int、short、double、long),当你在JavaScript中调用Java对象的foo方法时,Java会自动选择最匹配你传入参数类型的方法来执行。

java
//Java
void foo(int arg);
void foo(short arg);
void foo(double arg);
void foo(long arg);
js
//JavaScript
javaObject.foo(1);              // will call foo(short);
javaObject.foo(Math.pow(2,16)); // will call foo(int);
javaObject.foo(1.1);            // will call foo(double);
javaObject.foo(Math.pow(2,32)); // will call foo(long);

如果你想要强制选择调用某个特定类型的Java方法,可以使用javaObject['methodName(paramTypes)']的语法来显式选择方法重载,参数类型之间用逗号分隔,对象类型需要完全限定。比如:

js
javaObject['foo(int)'](1);
javaObject['foo(long)'](1);
javaObject['foo(double)'](1);

需要注意的是,传入的参数值必须符合对应方法的参数类型。如果你想改变参数传递的默认行为,可以使用自定义的目标类型映射来覆盖。

此外,在方法重载不明确或无法自动解析时,你可以使用显式方法选择。比如:

java
//Java
void sort(List<Object> array, Comparator<Object> callback);
void sort(List<Integer> array, IntBinaryOperator callback);
void consumeArray(List<Object> array);
void consumeArray(Object[] array);
js
//JavaScript
var array = [3, 13, 3, 7];
var compare = (x, y) => (x < y) ? -1 : ((x == y) ? 0 : 1);

// throws TypeError: Multiple applicable overloads found
javaObject.sort(array, compare);
// explicitly select sort(List, Comparator)
javaObject['sort(java.util.List,java.util.Comparator)'](array, compare);

// will call consumeArray(List)
javaObject.consumeArray(array);
// explicitly select consumeArray(Object[])
javaObject['consumeArray(java.lang.Object[])'](array);

注意:当前无法显式选择构造函数重载。

7.4.6 数组访问

脚本模块支持在 JavaScript 代码创建 Java 数组。支持两种模式:

js
//模式1 pattern
var JArray = Java.type('java.lang.reflect.Array');
var JString = Java.type('java.lang.String');
var sarr = JArray.newInstance(JString, 5);


//模式2  pattern
var IntArray = Java.type("int[]");
var iarr = new IntArray(5);

创建的数组是 Java 类型,但可以在 JavaScript 代码中使用:

js
iarr[0] = iarr[iarr.length] * 2;

7.4.7 Map访问

在脚本引擎中,您可以创建和访问 Java Map,例如java.util.HashMap:

js
var HashMap = Java.type('java.util.HashMap');
var map = new HashMap();
map.put(1, "a");
map.get(1);

脚本引擎中支持迭代此类映射:

js
for (var key in map) {
    print(key);
    print(map.get(key));
}

7.4.8 列表访问

在脚本引擎中,可以创建和访问 Java 列表,例如java.util.ArrayList:

js
var ArrayList = Java.type('java.util.ArrayList');
var list = new ArrayList();
list.add(42);
list.add("23");
list.add({});

for (var idx in list) {
    print(idx);
    print(list.get(idx));
}

7.4.9 字符串访问

脚本引擎可以创建具有 Java 互操作性的 Java 字符串。字符串的长度可以通过属性查询length(注意length是一个值属性,不能作为函数调用):

js
var javaString = new (Java.type('java.lang.String'))("Java");
javaString.length === 4;

请注意:脚本引擎内部使用Java字符串来表示JavaScript字符串,因此在这种情况下,代码中的"Java"与使用Java类型创建的字符串实际上是一样的,无法在语义上区分它们。

7.4.10 迭代属性

Java 类和 Java 对象的属性(字段和方法)可以使用 JavaScript的for..in 循环进行迭代:

js
var m = Java.type('java.lang.Math')
for (var i in m) { print(i); }

//结果
> E
> PI
> abs
> sin
> ...

7.4.11 脚本里使用Java对象的例子

js
//调用Java graphics画一个矩形图片,并返回图片base64编码
export function createImage() {
    let width=100;
    let height=100;
    var BufferedImage = Java.type("java.awt.image.BufferedImage");
    var ByteArrayOutputStream=Java.type("java.io.ByteArrayOutputStream");
    var ImageIO=Java.type("javax.imageio.ImageIO");
    var Base64=Java.type("java.util.Base64");
    var Color=Java.type("java.awt.Color");
    //
    var image = new BufferedImage(100, 100, BufferedImage.TYPE_INT_BGR);
    var graphics = image.getGraphics();
    graphics.setColor(new Color(255, 0, 0));
    graphics.fillRect(1, 1, width - 1, height - 1);
    var os=new ByteArrayOutputStream();
    ImageIO.write(image, "jpg", os);
    let content=os.toByteArray();
    let base64=Base64.getEncoder().encodeToString(content);
    return base64;
}