如何在 Clojure 中调用重载的 Java 方法 [英] How do I call overloaded Java methods in Clojure

查看:32
本文介绍了如何在 Clojure 中调用重载的 Java 方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

对于此示例 Java 类:

For this example Java class:

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 对象中.

When I start Clojure and try to call the test(int) method, the test(Object) method is called instead, because Clojure automatically boxes the integer into a java.lang.Integer object.

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

How do I force Clojure to call the test(int) method?

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

我想在 AWT 中调用像 Component.add(Component comp, int index) 这样的方法,而是继续调用 add(Component comp, Object constraint),所以我工具栏上的按钮总是以错误的顺序出现.

I want to call methods like Component.add(Component comp, int index) in AWT, but instead keep calling add(Component comp, Object constraints), so the buttons on my toolbar always appear in the wrong order.

推荐答案

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

A discussion is going on in the #clojure channel on Freenode just now on this very topic. Chris Houser (who was going to post an answer, but ultimately decided he was too busy to do it) has posted a Gist which demonstrates what happens with a boolean vs. Object overloaded method; it turns out that in some scenarios, in addition to a (boolean ...) cast, a type hint is required. The discussion was quite enlightening, with a few dark corners of Clojure compilation process becoming nicely illuminated. (See links to IRC log below.)

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

Basically, if an object is created right in the method-calling form -- (.foo (Foo.) ...), say -- that type hint is not necessary; it is likewise not necessary if the object has been constructed as a value for a local in an enclosing let form (see update 2 below and my version of the Gist). If the object is obtained by Var lookup, though, a type hint is required -- which can be provided either on the Var itself or, at the call site, on the symbol used to refer to the Var.

来自 Gist 的 Java 代码:

The Java code from the Gist:

package mypkg;

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

还有 Clojure 代码:

And the Clojure code:

(.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 上的类型提示才能编译直接方法调用.否则,似乎会生成基于反射的代码,这显然无法跟踪这样一个事实,即参数在此过程中应该是原始的.

Note how the Clojure compiler needs a type hint on u to be able to compile a direct method call. Otherwise reflection-based code seems to be generated, which apparently loses track of the fact that the argument is meant to be a primitive along the way.

我的补充如下(这里是我对上述 Gist 的分支).

My additions follow (and here's my fork of the above Gist).

;; 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 发布了要点 半小时后,之后的讨论越来越有趣.

The topic was first brought up at this point. Chouser posted the Gist half an hour later, with the discussion becoming more and more interesting after that.

这篇关于如何在 Clojure 中调用重载的 Java 方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆