从 Nashorn 引擎中的 js 代码访问静态 Java 变量
Access static Java variables from js code in Nashorn engine
在 Java 8 中尝试将旧代码 运行 Rhino 引擎移植到 Nashorn 时,我遇到了麻烦,无法从 运行 js 脚本访问静态 properties/methods .如果我使用 Rhino,它运行完美。我不知道新的 Nashorn 引擎的实现会发生什么。
import javax.script.*;
public class StaticVars {
public static String myname = "John\n";
public static void main(String[] args) {
try{
ScriptEngine engine;
ScriptEngineManager manager = new ScriptEngineManager();
engine=System.getProperty("java.version").startsWith("1.8")?
manager.getEngineByName("Nashorn") : //j1.8_u51
manager.getEngineByName("JavaScript"); //j1.7
engine.put("staticvars", new StaticVars());
engine.eval("print(staticvars.myname);");
//print "John" if ran with java 7
//print "undefined" if ran with java 8
} catch(Exception e){e.printStackTrace();}
}
}
在 Nashorn 中,您无法通过 class 实例访问 class 静态成员。有多种方法可以获得静力学。您可以获得一个既充当构造函数又充当静态命名空间的类型对象,就像类型名称在 Java:
中的作用一样
var StaticVars = Java.type("StaticVars"); // use your full package name if you have it
print(StaticVars.myname);
或者,传入一个 java.lang.Class
对象并使用 .static
伪 属性 访问静态:
engine.put("StaticVarsClass", StaticVars.class);
其次是:
var StaticVars = StaticVarsClass.static;
print(StaticVars.myname);
在脚本中。一般来说,.static
是.class
的逆运算:
var BitSet = Java.type("java.util.BitSet");
var bitSetClass = BitSet.class; // produces a java.lang.Class object, just like in Java
print(BitSet === bitSetClass.static); // prints true
var bitSet = new BitSet(); // type object creates a new bitset when used as a constructor
var thisWontWork = new bitSetClass(); // java.lang.Class can't be used as a constructor.
如您所见,我们区分三个概念:
- 运行时 class 个对象,它们是
java.lang.Class
的实例。它们并不特殊,您只能对它们使用 Class
API(.getSuperclass()
、.getName()
等)
- classes 本身的实例(您可以访问实例成员的普通对象)
- type 对象,它们既是它们所代表的 classes 的静态成员的命名空间,也是构造函数。 Java 中与它们最接近的等价物是源代码中使用的 class 的名称;在 Java脚本中它们是实际对象。
这实际上产生了最少的歧义,因为一切都在它的位置,并且最接近 Java 平台习语。
这不是 js 应有的工作方式。我认为这是 Nashorn 中的一个设计错误。假设你有一个混合的 util 将 vars 从一些 java 运行时系统传递给 js 脚本。该对象包含一个静态方法 fmtNumber(someString) 和一个对象方法 jutil.getFormVar(someString)。用户不需要知道 Java 正在为这个平台服务。您只需告诉他们 jutil 是属于框架 foo 的 "system hook"。作为这个框架的用户,我不关心它是否是静态的。我是一名 js 开发人员,我不知道静态与否。我想快速编写一些脚本。这就是 rhino 中的代码的样子。
var x = jutil.getFormVar("x");
print(jutil.fmtNumber(x));
现在在nashorn中我必须区分它们。更糟糕的是,我什至必须教育我的用户区分它们并教给他们 java 个术语,他们可能不知道这些术语,因为这就是抽象层的全部意义所在:一个无需了解底层的自包含系统机制。这种区别是认知超载的方式,除了 java 开发人员为他们自己编写脚本之外,你没有考虑其他用例,他们可能不会这样做,因为他们已经知道一种叫做 Java 的好语言。作为 Java 开发人员,您正在考虑实现的形式,而您应该考虑如何在后台使用 Java 平台的强大功能,向 JS 开发人员隐藏所有令人讨厌的细节。如果 Web 开发人员需要区分浏览器中的静态 C++ 实现,他会怎么说?
在 Java 8 中尝试将旧代码 运行 Rhino 引擎移植到 Nashorn 时,我遇到了麻烦,无法从 运行 js 脚本访问静态 properties/methods .如果我使用 Rhino,它运行完美。我不知道新的 Nashorn 引擎的实现会发生什么。
import javax.script.*;
public class StaticVars {
public static String myname = "John\n";
public static void main(String[] args) {
try{
ScriptEngine engine;
ScriptEngineManager manager = new ScriptEngineManager();
engine=System.getProperty("java.version").startsWith("1.8")?
manager.getEngineByName("Nashorn") : //j1.8_u51
manager.getEngineByName("JavaScript"); //j1.7
engine.put("staticvars", new StaticVars());
engine.eval("print(staticvars.myname);");
//print "John" if ran with java 7
//print "undefined" if ran with java 8
} catch(Exception e){e.printStackTrace();}
}
}
在 Nashorn 中,您无法通过 class 实例访问 class 静态成员。有多种方法可以获得静力学。您可以获得一个既充当构造函数又充当静态命名空间的类型对象,就像类型名称在 Java:
中的作用一样var StaticVars = Java.type("StaticVars"); // use your full package name if you have it
print(StaticVars.myname);
或者,传入一个 java.lang.Class
对象并使用 .static
伪 属性 访问静态:
engine.put("StaticVarsClass", StaticVars.class);
其次是:
var StaticVars = StaticVarsClass.static;
print(StaticVars.myname);
在脚本中。一般来说,.static
是.class
的逆运算:
var BitSet = Java.type("java.util.BitSet");
var bitSetClass = BitSet.class; // produces a java.lang.Class object, just like in Java
print(BitSet === bitSetClass.static); // prints true
var bitSet = new BitSet(); // type object creates a new bitset when used as a constructor
var thisWontWork = new bitSetClass(); // java.lang.Class can't be used as a constructor.
如您所见,我们区分三个概念:
- 运行时 class 个对象,它们是
java.lang.Class
的实例。它们并不特殊,您只能对它们使用Class
API(.getSuperclass()
、.getName()
等) - classes 本身的实例(您可以访问实例成员的普通对象)
- type 对象,它们既是它们所代表的 classes 的静态成员的命名空间,也是构造函数。 Java 中与它们最接近的等价物是源代码中使用的 class 的名称;在 Java脚本中它们是实际对象。
这实际上产生了最少的歧义,因为一切都在它的位置,并且最接近 Java 平台习语。
这不是 js 应有的工作方式。我认为这是 Nashorn 中的一个设计错误。假设你有一个混合的 util 将 vars 从一些 java 运行时系统传递给 js 脚本。该对象包含一个静态方法 fmtNumber(someString) 和一个对象方法 jutil.getFormVar(someString)。用户不需要知道 Java 正在为这个平台服务。您只需告诉他们 jutil 是属于框架 foo 的 "system hook"。作为这个框架的用户,我不关心它是否是静态的。我是一名 js 开发人员,我不知道静态与否。我想快速编写一些脚本。这就是 rhino 中的代码的样子。
var x = jutil.getFormVar("x");
print(jutil.fmtNumber(x));
现在在nashorn中我必须区分它们。更糟糕的是,我什至必须教育我的用户区分它们并教给他们 java 个术语,他们可能不知道这些术语,因为这就是抽象层的全部意义所在:一个无需了解底层的自包含系统机制。这种区别是认知超载的方式,除了 java 开发人员为他们自己编写脚本之外,你没有考虑其他用例,他们可能不会这样做,因为他们已经知道一种叫做 Java 的好语言。作为 Java 开发人员,您正在考虑实现的形式,而您应该考虑如何在后台使用 Java 平台的强大功能,向 JS 开发人员隐藏所有令人讨厌的细节。如果 Web 开发人员需要区分浏览器中的静态 C++ 实现,他会怎么说?