推广 热搜: csgo  vue  angelababy  2023  gps  新车  htc  落地  app  p2p 

介绍 Nashorn —— Java 8 JavaScript 引擎

   2023-08-01 网络整理佚名2130
核心提示:方法和函数可以通过点运算符或方括号运算符来调用:当使用重载参数调用方法时,传递可选参数类型()会指定所调用的具体方法。可以在对象上定义方法,每当访问未定义属性或调用未定义方法时,将调用该方法:这里我们定义了一个名为math的对象,其中有一个名为的函数。下面的例子将参数类型从改为,我们可以从传入的对象中获得一些信息。当向这个方法传递对象(哈希表)时,在Java中可以访问其属性:

1

function increment(in) ++in

条件捕获语句

可以添加仅在指定条件为真时执行的特定 catch 子句:

1
2
3
4
5
6
7

try {
throw "BOOM";
} catch(e if typeof e === 'string') {
print("String thrown: " + e);
} catch(e) {
print("this shouldn't happen!");
}

使用 来设置对象原型

定义了一个 API 扩展,使我们能够更改对象的原型:

1

Object.setPrototypeOf(obj, newProto);

该函数通常被认为是 .. 的更好选择,因为它应该是在所有代码中设置对象原型的首选方法。

表达式和数据流

每个人都喜欢并直播——也! 虽然 5.1 没有 Java8 表达式的简化箭头语法,但我们可以在任何接受表达式的地方使用函数文字。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

var list = new java.util.ArrayList();
list.add("a1");
list.add("a2");
list.add("a3");
list.add("b1");
list.add("b2");
list.add("b3");
list.add("c1");
list.add("c2");
list.add("c3");


list
.stream()
.filter(function(el) {
return el.startsWith("a");
})
.sorted()
.forEach(function(el) {
print(el);
});
// a1, a2, a3

类继承

Java类型可以很容易地被Java继承。 您甚至可以在脚本中创建多线程代码,如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

var Runnable = Java.type('java.lang.Runnable');
var Printer = Java.extend(Runnable, {
run: function() {
print('printed from a separate thread');
}
});

var Thread = Java.type('java.lang.Thread');
new Thread(new Printer()).start();

new Thread(function() {
print('printed from another thread');
}).start();

// printed from a separate thread
// printed from another thread

函数重载

方法和函数可以使用点或括号运算符调用:

1
2
3
4

var System = Java.type('java.lang.System');
System.out.println(10); // 10
System.out["println"](11.0); // 11.0
System.out["println(double)"](12); // 12.0

当调用重载参数的方法时,传递可选参数 type() 指定被调用的具体方法。

爪哇豆

您可以简单地使用属性名称来获取或设置 Java Bean 的值,而无需显式调用 或 :

1
2
3
4

var Date = Java.type('java.util.Date');
var date = new Date();
date.year += 1900;
print(date.year); // 3918

属性绑定

两个不同对象的属性可以绑定在一起:

1
2
3
4
5
6
7
8

var o1 = {};
var o2 = { foo: 'bar'};

Object.bindProperties(o1, o2);

print(o1.foo); // bar
o1.foo = 'rab';
print(o2.foo); // rab

字符串扩展

原型上提供了两个简单但非常有用的扩展。 这些是求和函数,它们返回删除了空格的副本:

1
2

print("   hello world".trimLeft());
print("hello world ".trimRight());

地点

通过全局变量可以获取当前的文件名、目录和行,并且:

1

print(__FILE__, __LINE__, __DIR__);

进口范围

有时一次导入多个 Java 包很方便。 我们可以将类与 with 语句一起使用。 导入包的所有类文件都可以在 with 语句的本地范围内访问。

1
2
3
4
5

var imports = new Javaimporter(java.io, java.lang);
with (imports) {
var file = new File(__FILE__);
System.out.println(file.getAbsolutePath());
}

数组转换

以下代码将 Java List 转换为本机数组:

1
2
3
4
5
6
7

var javaList = new java.util.ArrayList();
javaList.add("1");
javaList.add("2");
javaList.add("3");
var jsArray = Java.from(javaList);
print(jsArray); // 1, 2, 3
print(Object.prototype.toString.call(jsArray)); // [object Array]

以下代码执行相反的操作:

1

var javaArray = Java.to([3, 5, 7, 11], "int[]");

访问超类

通常很难访问 中的重写成员,因为 中不存在 Java 的 super 关键字。 幸运的是,有一套补救措施。

首先我们需要在Java代码中定义超类:

1
2
3
4
5
6

class SuperRunner implements Runnable {
@Override
public void run() {
System.out.println("super run");
}
}

下面我已经介绍了。 创建新实例时要注意语法:重写成员的语法取自Java的匿名对象。

1
2
3
4
5
6
7
8
9
10
11
12
13

var SuperRunner = Java.type('my.package.SuperRunner');
var Runner = Java.extend(SuperRunner);

var runner = new Runner() {
run: function() {
Java.super(runner).run();
print('my run');
}
}
runner.run();

// super run
// my run

我们通过 Java.super() 扩展调用了重写的 .run() 方法。

神奇和

可以在对象上定义方法,每当访问未定义的属性或调用未定义的方法时都会调用这些方法:

1
2
3
4
5
6
7
8
9
10
11
12

var demo = {
__noSuchProperty__: function (propName) {
print("Accessed non-existing property: " + propName);
},

__noSuchMethod__: function (methodName) {
print("Invoked non-existing method: " + methodName);
}
};

demo.doesNotExist;
demo.callNonExistingMethod()

这将输出:

1
2

Accessed non-existing property: doesNotExist
Invoked non-existing method: callNonExistingMethod

java.

使用这个函数,我们可以获得一个与Java JSON库的期望兼容的对象。 代码如下所示:

1
2
3
4
5
6
7

Object obj = engine.eval("Java.asJSonCompatible(
{ number: 42, greet: 'hello', primes: [2,3,5,7,11,13] })");
Map map = (Map)obj;

System.out.println(map.get("greet"));
System.out.println(map.get("primes"));
System.out.println(List.class.isAssignableFrom(map.get("primes").getClass()));

这将输出:

1
2

hello
[2, 3, 5, 7, 11, 13]

加载脚本

您可以在脚本引擎中加载其他文件:

1

load('classpath:script.js');

或者通过 URL 加载脚本:

1

load('/script.js');

请记住,没有名称空间的概念,因此所有内容都堆积到全局环境中。 这使得加载的脚本可能与您的代码或它们之间存在命名冲突。 这可以通过使用以下函数来最小化:

1
2

var math = loadWithNewGlobal('classpath:math_module.js')
math.increment(5);

.js文件内容如下:

1
2
3
4
5
6
7

var math = {
increment: function(num) {
return ++num;
}
};

math;

这里我们定义了一个名为 math 的对象,并在其中调用了一个函数。 使用这种范例,我们可以实现基本的模块化。

将本机对象传递给 Java 时,您使用类,它们实际上是底层对象的 Java 表示。 实现Map接口,位于jdk..api中。 该包中的类可以在 Java 代码中使用。

下面的例子将参数类型从 改为 ,我们可以从传入的对象中获取一些信息。

1
2
3
4

static void fun(scriptObjectMirror mirror) {
System.out.println(mirror.getClassName() + ": " +
Arrays.toString(mirror.getOwnKeys(true)));
}

当将对象(哈希表)传递给此方法时,可以在 Java 中访问其属性:

1
2
3
4
5
6

MyJavaClass.fun({
foo: 'bar',
bar: 'foo'
});

// Object: [foo, bar]

我们还可以调用Java中的函数。 让我们首先定义一个具有属性和函数的类型。

1
2
3
4
5
6
7

function Person(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
this.getFullName = function() {
return this.firstName + " " + this.lastName;
}
}

方法可以通过() 来调用。

1
2
3

static void fun(scriptObjectMirror person) {
System.out.println("Full Name is: " + person.callMember("getFullName"));
}

当将 new 传递给 Java 方法时,我们会在控制台上看到预期的输出:

1
2
3
4

var person = new Person("Peter", "Parker");
MyJavaClass.fun(person);

// Full Name is: Peter Parker

限制脚本访问特定 Java 类

jdk..api..接口通过运行脚本来限制对特定Java类的访问,提供对Java类的代码访问的细粒度控制。 示例代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38

import javax.script.scriptEngine;
import jdk.nashorn.api.scripting.ClassFilter;
import jdk.nashorn.api.scripting.NashornscriptEngineFactory;

public class MyClassFilterTest {

class MyCF implements ClassFilter { // 创建类过滤器
@Override
public boolean exposeToscripts(String s) {
if (s.equals("java.io.File")) {
return false;
}
return true;
}
}

public void testClassFilter() {

final String script =
"print(java.lang.System.getProperty(\"java.home\"));" +
"print(\"Create file variable\");" +
"var File = Java.type(\"java.io.File\");";

NashornscriptEngineFactory factory = new NashornscriptEngineFactory();

scriptEngine engine = factory.getscriptEngine(new MyClassFilterTest.MyCF());

try {
engine.eval(script);
} catch (Exception e) {
System.out.println("Exception caught: " + e.toString());
}
}

public static void main(String[] args) {
MyClassFilterTest myApp = new MyClassFilterTest();
myApp.testClassFilter();
}

最终这会引发 java.lang.on 异常。

命令行脚本

如果您对编写命令行(shell)脚本感兴趣,请尝试一下 Nake。 Nake 是 Java 8 的简化构建工具。您只需在特定于项目的任务中定义任务,然后通过在命令行中键入 bare -- 来执行它们。 任务以脚本模式编写和运行,因此您可以使用终端、JDK8 API 和任意 Java 库的全部功能。

对于 Java 开发人员来说,编写命令行脚本从未如此简单......

本文部分内容来自:

 
反对 0举报 0 收藏 0 打赏 0评论 0
 
更多>同类资讯
推荐图文
推荐资讯
点击排行
网站首页  |  关于我们  |  联系方式  |  使用协议  |  版权隐私  |  网站地图  |  排名推广  |  广告服务  |  积分换礼  |  网站留言  |  RSS订阅  |  违规举报
Powered By DESTOON