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 是一个 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的reflector在有多种重载时随机选择一个这种行为既不符合直观也不受欢迎。

在我看来,最合理的做法是
- 如果可能,选择最具体的类型(例如,如果可用的类型是(Object, CharSequence, String)且反射类型是StringBuffer,则使用CharSequence而不是Object)。
- 如果可能,选择最宽的原生类型(例如,在这种情况下我们将使用long而不是int)
- 如果无法解决冲突,则抛出“找到多个匹配的方法”异常(这已在某些情况下发生)

(我仍然对之前阅读/修复Reflector.java和Compiler.java中复杂的野兽式的反射部分的经历感到恐惧,所以我提出这个想法,并没有打算自己进行这项工作:))

0

评论者:alexmiller

我认为subsumes检查实际上试图实现你的选项#1——这是一个两种情况下的参数类型没有层次关系的案例。可能选项#2更有意义,即表达偏好,尽管在“最广泛”没有意义的情况下确实存在,但不确定这个的一般形式是什么。

0

评论者:bronsa

为了明确,那不是一个不同选项的列表,而是一系列步骤。
即如果可能从层次结构中选择最具体的类型,则这样做;否则如果不是基本类型则选择最广泛的,否则失败

0

评论者:jafingerhut

可能与CLJ-1212相同,或者至少有一定的相似性。

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