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

对于此示例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) ,因此工具栏上的按钮总是以错误的顺序出现。

关于Freenode的#clojure频道正在讨论这个话题。 克里斯·豪瑟(谁会发布一个答案,但最终决定他太忙了,不能这么做)发布了一个Gist ,它演示了booleanObject重载方法会发生什么。 事实certificate,在某些情况下,除了(boolean ...)强制转换之外,还需要类型提示。 讨论非常具有启发性,Clojure编译过程的一些黑暗角落变得非常明亮。 (参见下面的IRC日志链接。)

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

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进行类型提示才能编译直接方法调用。 否则,似乎会生成基于reflection的代码,这显然会忽略这样一个事实,即参数在整个过程中都是一个原始的。

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

 ;; 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 ,之后讨论变得越来越有趣。

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

Clojure中的数字通常是盒装的(int => Integer),除非你特别要求原语。

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