如何在Clojure中实现Java接口

如何在Clojure中实现Java接口,java,clojure,Java,Clojure,如何创建一个Clojure对象来实现这个接口,然后从Java代码中调用它 public interface Doer { public String doSomethin(String input); } Doer clojureDoer = ?; String output = clojureDoer.doSomethin(input); 有代理人 请参阅代理宏。举一些例子。第页也有介绍 proxy返回实现Doer的对象。现在,要在Java中访问它,您必须使用gen class使C

如何创建一个Clojure对象来实现这个接口,然后从Java代码中调用它

public interface Doer {
   public String doSomethin(String input);
}

Doer clojureDoer = ?;

String output = clojureDoer.doSomethin(input);
有代理人 请参阅
代理
宏。举一些例子。第页也有介绍

proxy
返回实现
Doer
的对象。现在,要在Java中访问它,您必须使用
gen class
使Clojure代码可以从Java调用。这个问题的答案包括了这一点

具有gen类
现在将其保存为
doer\u clj.clj
mkdir类
,并通过调用REPL
(需要'doer clj'(编译'doer clj)
来编译它。您应该发现
DoerClj.class
classes
directory

reify
是实现接口的首选工具-
proxy
是一种重载、陈旧且缓慢的工具,因此应尽可能避免使用。实现如下所示:

(reify Doer
  (doSomethin [this input]
    (...whatever...)))

对于这个问题的更一般的理解,当您需要某种Java互操作时,这个图非常有用:

如果在界面中定义了
doSomethin()
,则不应在
:methods
中提及它。引自:

截至年月日,首选方法如下。假设在类路径上有Clojure 1.6 jar和以下Clojure文件(或其编译后的等效文件):

然后,您可以从Java访问它,如下所示:

package my.other.java.package.or.maybe.the.same.one;

import my.java.package.Doer;
import clojure.lang.IFn;
import clojure.java.api.Clojure;

public class ClojureDoerUser {
    // First, we need to instruct the JVM to compile/load our
    // Clojure namespace. This should, obviously, only be done once.
    static {
        IFn require = Clojure.var("clojure.core", "require");
        require.invoke(Clojure.read("my.clojure.namespace"));
        // Clojure.var() does a somewhat expensive lookup; if we had more than
        // one Clojure namespace to load, so as a general rule its result should
        // always be saved into a variable.
        // The call to Clojure.read is necessary because require expects a Clojure
        // Symbol, for which there is no more direct official Clojure API.
    }

    // We can now lookup the function we want from our Clojure namespace.
    private static IFn doerFactory = Clojure.var("my.clojure.namespace", "reify-doer");

    // Optionally, we can wrap the doerFactory IFn into a Java wrapper,
    // to isolate the rest of the code from our Clojure dependency.
    // And from the need to typecast, as IFn.invoke() returns Object.
    public static Doer createDoer() {
        return (Doer) doerFactory.invoke();
    }
    public static void main(String[] args) {
        Doer doer = (Doer) doerFactory.invoke();
        doer.doSomethin("hello, world");
    }
}

酷。然后可以从Java调用clojureDoer对象吗?请注意我的问题中的“Doer clojureDoer=?”。我应该在“?”中加入什么使程序工作。您提供的链接显示了如何将clojure对象作为静态类导入。谢谢在这种情况下,你可能会对我刚才补充的回答的后半部分更感兴趣。它是
代理
-免费的,似乎更适合您的情况。如果第二个解决了你的问题,我想我会删除前半个。。我必须将Doer放入一个包中,因为编译器正在寻找java.lang.Doer。我在线程“main”java.lang.ClassFormatError中遇到异常:当我执行Doer Doer=new DoerClj()时,类文件DoerClj中的方法名和签名重复;只是想澄清一下-你用的是哪个Clojure版本?奇怪。尝试编译这个基于接口的简单代码。当我
(需要'doer clj'(编译'doer clj)
时,我可以调用
DoerClj.run()
,没有任何问题。感谢大家帮助我!我最终使用了Reify,并在clojure中编写了主函数。clojure非常酷!我以前也遇到过一次,但我没有意识到这是一个多么好的资源。谢谢你指出这一点。谢谢@Gary Verhaegen;)
(reify Doer
  (doSomethin [this input]
    (...whatever...)))
:methods [ [name [param-types] return-type], ...]
The generated class automatically defines all of the non-private
methods of its superclasses/interfaces. This parameter can be used
to specify the signatures of additional methods of the generated
class. Static methods can be specified with ^{:static true} in the
signature's metadata. Do not repeat superclass/interface signatures
here.
(ns my.clojure.namespace
  (:import [my.java.package Doer]))

(defn reify-doer
  "Some docstring about what this specific implementation of Doer
  does differently than the other ones. For example, this one does
  not actually do anything but print the given string to stdout."
  []
  (reify
    Doer
    (doSomethin [this in] (println in))))
package my.other.java.package.or.maybe.the.same.one;

import my.java.package.Doer;
import clojure.lang.IFn;
import clojure.java.api.Clojure;

public class ClojureDoerUser {
    // First, we need to instruct the JVM to compile/load our
    // Clojure namespace. This should, obviously, only be done once.
    static {
        IFn require = Clojure.var("clojure.core", "require");
        require.invoke(Clojure.read("my.clojure.namespace"));
        // Clojure.var() does a somewhat expensive lookup; if we had more than
        // one Clojure namespace to load, so as a general rule its result should
        // always be saved into a variable.
        // The call to Clojure.read is necessary because require expects a Clojure
        // Symbol, for which there is no more direct official Clojure API.
    }

    // We can now lookup the function we want from our Clojure namespace.
    private static IFn doerFactory = Clojure.var("my.clojure.namespace", "reify-doer");

    // Optionally, we can wrap the doerFactory IFn into a Java wrapper,
    // to isolate the rest of the code from our Clojure dependency.
    // And from the need to typecast, as IFn.invoke() returns Object.
    public static Doer createDoer() {
        return (Doer) doerFactory.invoke();
    }
    public static void main(String[] args) {
        Doer doer = (Doer) doerFactory.invoke();
        doer.doSomethin("hello, world");
    }
}