如何在Clojure中调用重载的Java方法

2022-09-03 06:10:11

对于此示例 Java 类:

package foo;
public class TestInterop
{   public String test(int i)
    { return "Test(int)"; }

    public String test(Object i)
    { return "Test(Object)"; }
}

当我启动Clojure并尝试调用test(int)方法时,将调用test(Object)方法,因为Clojure会自动将整数框入java.lang.Integer对象中。

如何强制Clojure调用test(int)方法?

user=> (.test (new foo.TestInterop) 10)
"Test(Object)"

我想像AWT一样调用方法,但相反,请继续调用,因此工具栏上的按钮总是以错误的顺序显示。Component.add(Component comp, int index)add(Component comp, Object constraints)


答案 1

就在Freenode的#clojure频道上,关于这个话题的讨论正在进行中。Chris Houser(他本来打算发布一个答案,但最终决定他太忙了,无法做到这一点)发布了一个要点,演示了vs会发生什么。 重载方法;事实证明,在某些情况下,除了强制转换之外,还需要类型提示。讨论非常有启发性,Clojure编译过程中的几个黑暗角落变得很好。(请参阅下面的IRC日志链接。booleanObject(boolean ...)

基本上,如果一个对象是在方法调用形式中创建的,-- ,说 - 该类型提示不是必需的;如果对象已被构造为封闭形式的本地值,则同样没有必要(请参阅下面的更新2和我的Gist版本)。但是,如果对象是通过 Var 查找获得的,则需要一个类型提示 - 可以在 Var 本身上提供,也可以在调用站点上提供用于引用 Var 的符号上。(.foo (Foo.) ...)let

来自 Gist 的 Java 代码:

package mypkg;

public class Ugly {
    public Ugly(){}
    public String foo(boolean i) { return "bool: " + i; }
    public String foo(Object o) { return "obj: " + o; }
}

Clojure代码:

(.foo (mypkg.Ugly.) 5)
;=> "obj: 5"

(.foo (mypkg.Ugly.) true)
;=> "obj: true"

(.foo (mypkg.Ugly.) (boolean true))
;=> "bool: true"


(def u (mypkg.Ugly.))
(.foo u (boolean true))
;=> "obj: true"

(.foo #^mypkg.Ugly u (boolean true))
;=> "bool: true"

请注意,Clojure 编译器需要一个类型提示才能编译直接方法调用。否则,似乎会生成基于反射的代码,这显然忘记了参数是一个原始参数的事实。u

我的补充如下(这是我上述要点的分支)。

;; renamed mypkg.Ugly to foo.TestInterop2 when doing my tests
user> (let [t (foo.TestInterop2.)]
        (.foo t (boolean true)))
"bool: true"

;;; type-hinting the Var
user> (def #^foo.TestInterop2 x (foo.TestInterop2.))
#'user/x
user> (.foo x (boolean true))
"bool: true"

这个话题最初是在这一点上提出的。Chouser在半小时后发布了Gist,之后的讨论变得越来越有趣。


答案 2
user=> (.test (foo.TestInterop.) 10)
"Test(Object)"
user=> (.test (foo.TestInterop.) (int 10))
"Test(int)"

Clojure中的数字通常是装箱的(int = > Integer),除非您专门要求基元。

以下是有关Clojure中基元的更多信息。