为什么Java 8 Nashorn(JavaScript)的模运算返回0.0(双精度浮点数)而不是0(整数)?

8
考虑以下代码示例:
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;

public class Tester {

  public static void main( String[] args ) throws Exception {
      ScriptEngine se = new ScriptEngineManager().getEngineByName( "nashorn" );

      Object eval = se.eval( "5%5" );

      System.out.println( "eval = " + eval );
      System.out.println( "eval.getClass() = " + eval.getClass() );
  }
}

为什么会产生以下输出?
``` eval = 0.0 eval.getClass() = class java.lang.Double ```
结果类型是 `java.lang.Double`,这很奇怪。
如果余数不等于0,则正确返回 `java.lang.Integer`,例如 `5%2` 返回值为 `java.lang.Integer` 类型,值为1。
只有0是特殊的。尝试在 Firefox 32.0.2(FindBugs 控制台)中执行相同的 JavaScript 表达式可以正常工作并返回纯 0。
是否有任何方法可以强制 Nashorn 返回 Integer 类型而不是 Double?

1
JavaScript 只有浮点数类型的数字。 - Teemu
@Teemu谢谢你的意见,但这在这里有什么要紧吗?在内部可能是一个浮点数,但是它可以将其“转换”为整数,例如,5%2产生整数1。如果在这种情况下我得到了1.0,我会接受这样的解释。 - Piotr Nowicki
Firefox没有“投射”任何内容。这只是它如何显示浮点值1.0的问题。 - David P. Caldwell
1
好的,我认为我们有点偏离了主题。忘记强制转换/ Firefox等。问题仍然存在,即为什么5%2的结果是java.lang.Integer(1),而5%5的结果是java.lang.Double(0.0) - Piotr Nowicki
3个回答

6
JavaScript中没有整数。
ECMAScript第8节:类型开始:
引用:

ECMAScript语言类型是Undefined、Null、Boolean、String、Number和Object。

然后看ECMAScript第8.5节:数字类型
引用:

数字类型恰好有18437736874454810627个值,表示双精度64位格式IEEE 754值...(强调添加)

Firefox显示浮点值1为“1”而不是“1.0”的事实与此无关,会使你感到困惑。

1
谢谢您的回答。 我们忘记Firefox吧,因为我同意它可能会引起混淆。让我们专注于Nashorn,它应该实现ECMAScript LS。有时是java.lang.Integer,有时是java.lang.Double - Piotr Nowicki
1
非常好:感谢您将问题缩小到那个问题。这是我的看法:奇怪的是,它返回java.lang.Integer,因为所有JavaScript数字都是浮点数。我会看看能否解决这部分问题。我认为这是一个错误,可能会在未来的版本中更改,因此我可能会将我的东西包装在将所有内容转换为Double的东西中(我没有Java API在我面前,但是new Double()或Double.valueOf()或其他)。 - David P. Caldwell
2
或者更明确地说,我会将问题从“为什么它返回Double而不是Integer”改为“为什么它返回Integer而不是Double?” - David P. Caldwell
好的,非常感谢David。因此,Nashorn实现者所做的结果类型为Integer或Double之间的区分可能是相当误导人的。我希望它能够始终保持一致 - 要么它应该始终进行转换(因此在上面的问题中它应该始终是java.lang.Integer),要么它应该省略任何转换并只返回java.lang.Double - Piotr Nowicki
1
是的。我查看了代码,设计让我觉得,在我的学习水平上,返回Double可能是意图。请参阅http://hg.openjdk.java.net/nashorn/jdk8/nashorn/file/18edd7a1b166/src/jdk/nashorn/internal/codegen/types/NumberType.java获取源代码;`rem`(实现%)的返回值为Type.NUMBER,如果您访问(同一包)Type.java,您将看到它与Double相关联。但是,您将在NumberType中看到我们进入了字节码领域,其中包含所有visitInsn和OpCode等内容,这就是我暂时退出的地方。 :) - David P. Caldwell

6

即将发布的8u40更新 - 来源 http://hg.openjdk.java.net/jdk8u/jdk8u-dev/nashorn,修复了这个问题。但是,最好预期数值计算的结果为“java.lang.Number”(在Java接口中),并使用java.lang.Number方法进行转换,如intValue()、doubleValue()等。


非常感谢你的回答!很遗憾我不能接受所有人的答案。我已经接受了David的答案,因为他首先提出了这是一个错误,并深入研究了源代码。再次感谢。 - Piotr Nowicki

5
这是Nashorn文档关于将数字值从JavaScript传递给Java的说明:

如果目标类型不太具体(例如,Number),则只能期望它们为Number类型,...由于内部优化,数字可以是任何装箱类型

正如其他人已经指出的那样,JavaScript本身仅支持浮点值(即Number类型)。

非常感谢您提供的“由于内部优化,数字可以是任何框定类型”的部分! - Piotr Nowicki

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接