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

欢迎!请查看关于页面了解这个平台的工作方式。

0
Java Interop

在使用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的 reflektor在有多种重载可供选择时随机选择一个的行为既不符合直觉又不理想。

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

(我仍然对之前阅读/修改Reflector.java和Compiler.java中复杂的反射部分的经历感到恐惧,所以我提出这一点,没有意从未自己处理过这个问题:)

0

评论者:alexmiller

我认为子类化检查实际上是试图执行你的选项#1 - 这是一个两个案例中的参数类型没有层次关系的情况。可能#2会更合理 - 表达偏好,尽管“最宽类型”显然没有意义,所以不确定这一般形式是什么。

0

评论者:bronsa

为明确起见,那不是一个不同选项的列表,而是一个要采取的步骤的列表。
即:如果可能,从层次结构中选择最具体类型,否则如果类型是原始类型,选择最宽类型,否则失败。

0

评论者:jafingerhut

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

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