OpenJDK Nashorn与内置Nashorn的Array push类型转换差异问题
从JDK内置Nashorn迁移到OpenJDK Nashorn的数组类型转换问题
问题现象
将代码从JDK 11内置的Nashorn切换到OpenJDK Nashorn时,出现以下类型不一致问题:
var testArray = []; testArray.push(new java.lang.Long(1234)); // 结果:数组元素为java.lang.Double类型 var testTwoArray = [new java.lang.Long(1234)]; // 结果:数组元素为java.lang.Long类型
在JDK内置Nashorn中,第一条语句的结果是Integer类型,可正常调用要求List<Integer>的后端方法;但OpenJDK Nashorn中转为List<Double>,导致方法调用失败。仅在向空数组push Long类型时会触发该转换,其他场景类型均正常保留。
原因分析
这是OpenJDK Nashorn的特性而非bug:
- 空数组初始化时没有任何类型上下文,OpenJDK Nashorn会默认将其视为JS原生数组。当第一次push Java数值包装类(如Long)时,会自动转为JS原生的Number类型,而JS Number在Java层面对应
java.lang.Double。 - 直接用元素初始化数组时,Nashorn能从初始元素推断出数组的类型上下文,会保留原Java包装类的类型,不会进行自动转换。
解决方案
需要修改代码来规避自动类型转换,可选方案如下:
1. 避免使用空数组初始化
直接用第一个元素初始化数组,后续push的元素会自动沿用该类型:
var testArray = [new java.lang.Long(1234)]; testArray.push(new java.lang.Long(5678)); // 所有元素均为java.lang.Long类型
2. push时显式保留Java类型
在push时重新包装元素,确保类型不被转换:
var testArray = []; testArray.push(java.lang.Long.valueOf(1234)); // 或对已有Long对象重新包装 var longObj = new java.lang.Long(1234); testArray.push(java.lang.Long.valueOf(longObj.longValue()));
3. 使用Java集合替代JS数组
如果需要严格的类型控制,直接使用Java的集合类,明确指定元素类型:
var testList = new java.util.ArrayList(java.lang.Long.class); testList.add(new java.lang.Long(1234)); // 集合元素类型始终为java.lang.Long
测试用例验证
以下是完整测试用例,可复现该问题并验证解决方案:
var t1numberOne = java.lang.Long.valueOf('123'); var t1numberTwo = java.lang.Integer.valueOf('123'); var t1numberThree = java.lang.Double.valueOf('123'); print('No modification - int') print("One: {} - {}", t1numberOne.getClass(), t1numberOne); print("Two: {} - {}", t1numberTwo.getClass(), t1numberTwo); print("Three: {} - {}", t1numberThree.getClass(), t1numberThree); print('-----------------------------------------------------'); var t2numberOne = java.lang.Long.valueOf('123'); var t2numberTwo = java.lang.Integer.valueOf('123'); var t2numberThree = java.lang.Double.valueOf('123.7'); print('No modification - double') print("One: {} - {}", t2numberOne.getClass(), t2numberOne); print("Two: {} - {}", t2numberTwo.getClass(), t2numberTwo); print("Three: {} - {}", t2numberThree.getClass(), t2numberThree); print('-----------------------------------------------------'); var t3numberOne = java.lang.Long.valueOf('123'); var t3numberTwo = java.lang.Integer.valueOf('123'); var t3numberThree = java.lang.Double.valueOf('123'); var t3testArray = [t3numberOne, t3numberTwo, t3numberThree]; print('Adding to array - int!') print("One: {} - {}", t3testArray[0].getClass(), t3testArray[0]); print("Two: {} - {}", t3testArray[1].getClass(), t3testArray[1]); print("Three: {} - {}", t3testArray[2].getClass(), t3testArray[2]); print('-----------------------------------------------------'); var t4numberOne = java.lang.Long.valueOf('123'); var t4numberTwo = java.lang.Integer.valueOf('123'); var t4numberThree = java.lang.Double.valueOf('123.7'); var t4testArray = [t4numberOne.longValue(), t4numberTwo.intValue(), t4numberThree.doubleValue()]; print('Adding to array - double!') print("One: {} - {}", t4testArray[0].getClass(), t4testArray[0]); print("Two: {} - {}", t4testArray[1].getClass(), t4testArray[1]); print("Three: {} - {}", t4testArray[2].getClass(), t4testArray[2]); print('-----------------------------------------------------'); var t5testArray = []; t4testArray.forEach(function(entry){ t5testArray.push(entry); }) print('Copying Long elements from other long array using .push()') print("One: {} - {}", t5testArray[0].getClass(), t5testArray[0]); print("Two: {} - {}", t5testArray[1].getClass(), t5testArray[1]); print("Three: {} - {}", t5testArray[2].getClass(), t5testArray[2]); print('-----------------------------------------------------'); var t6NumberOne = java.lang.Long.valueOf('123'); var t6NumberTwo = java.lang.Long.valueOf('456'); var t6NumberThree = java.lang.Long.valueOf('789'); var t6testArray = [t6NumberOne, t6NumberTwo, t6NumberThree]; var t6testCopyArray = []; t6testArray.forEach(function(entry){ t6testCopyArray.push(entry); }) print('Copying Long elements from other long array using .push()') print("One Original: {} - {}", t6testArray[0].getClass(), t6testArray[0]); print("Two Original: {} - {}", t6testArray[1].getClass(), t6testArray[1]); print("Three Original: {} - {}", t6testArray[2].getClass(), t6testArray[2]); print('--') print("One Copied: {} - {}", t6testCopyArray[0].getClass(), t6testCopyArray[0]); print("Two Copied: {} - {}", t6testCopyArray[1].getClass(), t6testCopyArray[1]); print("Three Copied: {} - {}", t6testCopyArray[2].getClass(), t6testCopyArray[2]); print('-----------------------------------------------------'); var t7NumberOne = java.lang.Long.valueOf('123'); var t7NumberTwo = java.lang.Long.valueOf('456'); var t7NumberThree = java.lang.Long.valueOf('789'); var t7testArray = [t7NumberOne, t7NumberTwo, t7NumberThree]; var t7testCopyArray = []; t7testArray.forEach(function(entry){ t7testCopyArray.push(java.lang.Long.valueOf(entry)); }) print('Copying from other long array - converting to long during .push() (t7testCopyArray.push(java.lang.Long.valueOf(entry))') print("One Original: {} - {}", t7testArray[0].getClass(), t7testArray[0]); print("Two Original: {} - {}", t7testArray[1].getClass(), t7testArray[1]); print("Three Original: {} - {}", t7testArray[2].getClass(), t7testArray[2]); print('--') print("One Copied: {} - {}", t7testCopyArray[0].getClass(), t7testCopyArray[0]); print("Two Copied: {} - {}", t7testCopyArray[1].getClass(), t7testCopyArray[1]); print("Three Copied: {} - {}", t7testCopyArray[2].getClass(), t7testCopyArray[2]); print('-----------------------------------------------------'); var t8NumberOne = java.lang.Long.valueOf('123'); var t8NumberTwo = java.lang.Long.valueOf('456'); var t8NumberThree = java.lang.Long.valueOf('789'); var t8testArray = [t8NumberOne, t8NumberTwo, t8NumberThree]; var t8testCopyArray = []; t8testCopyArray.push(t8NumberOne); t8testCopyArray.push(t8NumberTwo); t8testCopyArray.push(t8NumberThree); print('Pushing Long elements into empty array using .push()') print("One Original: {} - {}", t8testArray[0].getClass(), t8testArray[0]); print("Two Original: {} - {}", t8testArray[1].getClass(), t8testArray[1]); print("Three Original: {} - {}", t8testArray[2].getClass(), t8testArray[2]); print('--') print("One Copied: {} - {}", t8testCopyArray[0].getClass(), t8testCopyArray[0]); print("Two Copied: {} - {}", t8testCopyArray[1].getClass(), t8testCopyArray[1]); print("Three Copied: {} - {}", t8testCopyArray[2].getClass(), t8testCopyArray[2]); print('-----------------------------------------------------'); var t9NumberOne = java.lang.Integer.valueOf('123'); var t9NumberTwo = java.lang.Integer.valueOf('456'); var t9NumberThree = java.lang.Integer.valueOf('789'); var t9testArray = [t9NumberOne, t9NumberTwo, t9NumberThree]; var t9testCopyArray = []; t9testCopyArray.push(t9NumberOne); t9testCopyArray.push(t9NumberTwo); t9testCopyArray.push(t9NumberThree); print('Pushing Integer elements into empty array using .push()') print("One Original: {} - {}", t9testArray[0].getClass(), t9testArray[0]); print("Two Original: {} - {}", t9testArray[1].getClass(), t9testArray[1]); print("Three Original: {} - {}", t9testArray[2].getClass(), t9testArray[2]); print('--') print("One Copied: {} - {}", t9testCopyArray[0].getClass(), t9testCopyArray[0]); print("Two Copied: {} - {}", t9testCopyArray[1].getClass(), t9testCopyArray[1]); print("Three Copied: {} - {}", t9testCopyArray[2].getClass(), t9testCopyArray[2]); print('-----------------------------------------------------');
内容的提问来源于stack exchange,提问作者Florian Johannes Pössl
相关产品推荐
相关产品推荐

