Rhino:Java 数字的行为不像 Javascript 数字
Posted
技术标签:
【中文标题】Rhino:Java 数字的行为不像 Javascript 数字【英文标题】:Rhino: Java numbers don't behave like Javascript numbers 【发布时间】:2015-07-22 23:38:31 【问题描述】:我的 javascript 程序中有一个可以访问的 Java 类的实例
public class ContentProvider
public Object c(int n)
switch (n)
case 1: return 1.1;
case 2: return 2.2;
case 3: return 3.3;
case 4: return "4";
case 5: return new java.util.Date();
return null;
这是 main() 中的代码:
ScriptEngineManager mgr = new ScriptEngineManager();
ScriptEngine engine = mgr.getEngineByName("JavaScript");
engine.put("ctx", new ContentProvider());
res = engine.eval("ctx.c(1)");
System.out.printf("rhino:> %s (%s)%n"
, res
, res != null ? res.getClass().getName() : null
);
简单的表达式ctx.c(1)
打印:
rhino:> 1.1 (java.lang.Double)
现在ctx.c(1) + ctx.c(2)
会发生什么:
rhino:> 1.12.2 (java.lang.String)
最后是(ctx.c(1) + ctx.c(2)) * ctx.c(3)
:
rhino:> nan (java.lang.Double)
Rhino 正在执行字符串连接而不是数字运算!以下程序按预期工作:
engine.put("a", 1.1);
engine.put("b", 2.2);
engine.put("c", 3.3);
res = engine.eval("(a + b) * c");
输出:
rhino:> 10,89 (java.lang.Double)
【问题讨论】:
天哪,居然有人正确同时使用了“java”和“javascript”标签! 但是为什么不试试engine.eval("typeof ctx.c(1)")
看看 JavaScript 认为的类型是什么?
typeof ctx.c(1) = object
@lunicon 不错的解决方案!请将其添加为答案 (doesn't matter if you are the OP as well) 并接受。
@lunicon 你可能想看看我的新答案,因为它更容易编码和维护
【参考方案1】:
我创建了一个值包装器:
public static class JSValue extends sun.org.mozilla.javascript.internal.ScriptableObject
Object value;
public JSValue(Object value)
this.value = value;
public String getClassName()
return value != null? value.getClass().getName(): null;
@Override
public Object getDefaultValue(Class typeHint)
if (typeHint == null || Number.class.isAssignableFrom(typeHint))
if (value instanceof Number)
return ((Number) value).doubleValue();
return toString();
@Override
public String toString()
return value != null? value.toString(): null;
还有一个编辑功能:
public static class ContentProvider
public Object c(int n)
... return new JSValue(1.1);
现在表达式按预期工作。谢谢大家。
【讨论】:
【参考方案2】:这是 Rhino 的一个奇怪特性:Java Number
与 engine.put("one", new Double(1))
的集合按预期工作,而 Java 方法的结果取决于方法本身声明的返回类型,使用反射 API 读取:
double
,则会转换为 Javascript 数字
否则它会像其他主机对象一样处理,+
表示连接,Object
就像您的示例一样,Double
您可以在当前Context
中的WrapFactory
上使用wrapFactory.setJavaPrimitiveWrap(false)
配置此行为。这样,Rhino 代码可以保存在程序的引导行中,并且不会弄乱ContentProvider
(我猜这是某种配置代理)
来自live Javadoc of WrapFactory.isJavaPrimitiveWrap()
默认情况下,该方法返回 true 以指示实例 字符串、数字、布尔值和字符应像任何其他值一样包装 Java 对象和脚本可以访问这些可用的任何 Java 方法 对象
因此您可以将此标志设置为false
以指示Java Number
应转换为Javascript 数字。只需要两行代码
Context ctx = Context.enter();
ctx.getWrapFactory().setJavaPrimitiveWrap(false);
这里是the Gist,里面有我用来测试的完整代码
【讨论】:
谢谢。它应该在文档中加粗。 同意。相反,我不得不调试和下载源代码。这似乎也是一个奇怪的默认值 我遇到了这个问题并搜索了所有文档但没有找到任何东西。谢谢你节省了我的时间。 更新:在 Rhino java7 中,它适用于每个 Number 类,bug 在最新的 Rhino 1.7.11 中,BigDecimal 和 BigInteger 没有包装!以上是关于Rhino:Java 数字的行为不像 Javascript 数字的主要内容,如果未能解决你的问题,请参考以下文章
使用 require.js 和 Java/Rhino 解析模块