Appearance
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;
}