2024 Clojure 状态调查! 中分享您的想法。

欢迎!有关如何使用本网站的更多信息,请参阅 关于 页面。

0
Java 互操作

这是在 Java 1.8 (Oracle 或 Open JDK) 中

`
weird-abs.core=> (Math/abs -10000000000000)
10000000000000
weird-abs.core=> (def a -10000000000000)

'weird-abs.core/a

weird-abs.core=> (Math/abs a)
1316134912
`

在 Java 1.7 中,返回了预期的结果(10000000000000)。

原因:似乎调用了 Math.abs(int)。 反射器考虑了 int 和 long 版本,但 Java 1.7 和 1.8 以不同的顺序返回这些签名,并选择了第一个找到的。

解决方案:使用提示或强制类型转换为 reflector 通知选择哪一个。

6 答案

0

评论由:alexmiller 提供

在第一种情况下,-10000000000000 是 long 类型,编译器明确找到 Math.abs(long)。

在第二种情况下,a 是 Object 对象,考虑所有 abs 签名(这在 Reflector.invokeMatchingMethod 中)。在 Java 1.7 和 1.8 中,都有找到 long 和 int 签名 "一致"。

在 Java 1.7 中,首先找到 long 版本并处理为匹配项,然后检查 int,Compiler.subsumes((link: int), (link: long)) 返回 false,因此 long 方法保持为匹配项。

在 Java 1.8 中,首先找到 int 版本并处理为匹配项,然后检查 long,Compiler.subsumes((link: long), (link: int)) 返回 false,因此 int 方法保持为匹配项。

这些建立在两个 JDK 上都是 false

(Compiler/subsumes (into-array [Long/TYPE]) (into-array [Integer/TYPE])) (Compiler/subsumes (into-array [Integer/TYPE]) (into-array [Long/TYPE]))

因此,真正的差异仅仅是考虑的顺序,这是 JDK 特定的。

可以按某种规范方式对考虑的签名进行排序,从而使此行为保持一致,或者可能有某种方式表达对两个签名的偏好。

无论如何,通过提示或转换类型消除这里的反射可以解决该问题——我认为在这种情况下,正确的结果能在Java 7中出现应归功于运气,而不是意图。

0

评论者:bronsa

在我看来,clojure的反射器在有多种重载可供选择时随机选择一种的非确定性行为既不符合直觉,也不令人满意。

我认为最合理的做法应该是
- 在可能的情况下选择最具体的类型(例如,如果可用的有(链接:Object,CharSequence,String),而反射的类型是StringBuffer,则使用CharSequence而不是Object)
- 在可能的情况下选择最宽的原始类型(例如,在这种情况下我们使用long而不是int)
- 如果冲突无法解决,则抛出More than one matching method found异常(这已在某些情况下发生)

(我仍然害怕之前的尝试阅读/修补那个复杂的“野兽”,即Reflector.java和Compiler.java中的反射部分,所以我提出这个建议,没有打算亲自解决这个问题:)

0

评论由:alexmiller 提供

我认为subsumes检查实际上已经试图执行你的选项#1——这是一个两种情况下参数类型没有层次关系的案例。选项#2可能更合理——表达偏好,尽管“最宽的”在某些情况下没有意义,所以不确定这是一个通用的形式。

0

评论者:bronsa

为了澄清,这不是一组不同的选项,而是要采取的一组步骤。
即:如果可能,从层次结构中挑选最具体的类型,否则,如果类型是原始的,挑选最宽的类型,否则失败

0

评论者:jafingerhut

可能与CLJ-1212相同,或者至少有一些共同点。

0
参考:https://clojure.atlassian.net/browse/CLJ-1921(由alexmiller报告)
...