请在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以不同的顺序返回这些签名,并且选择找到的第一个。

解决方法:使用提示或强制转换来通知反射器选择哪一个。

6个答案

0

评论由:alexmiller

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

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

在Java 1.7中,先找到了long版本,并被视为匹配,然后检查int,Compiler.subsumes((链接: int),(链接: long))返回false,导致long方法被保留为匹配。

在Java 1.8中,先找到int版本,并被视为匹配,然后检查long,Compiler.subsumes((链接: long),(链接: 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 报告)
...