12

目前,我有一个从 Java 调用的功能齐全的 Clojure 库。

我这样做的方式:我有一个文件,它使用 gen-class 将整个 API 包装为单个类的静态方法,并以 IPersistentVector 和 IPersistentMap 的形式传入和传出数据。

然而,现在我正在重构库并将功能置于各种协议后面。

我有四个协议,我们称它们为 A、B、C 和 D。还有两个定义记录 X 和 Y。X 和 Y 都实现了协议 A、B 和 C。而 Y 也实现了 D。

我需要做什么才能使这些对 Java 可用?这些是否可以作为接口和类自动使用?还是我仍然需要做相当于 gen-class 的操作才能将它们公开?

如果不是,那么 gen-class :methods 子句的等价物是什么,我在其中为方法的参数定义 Java 类型?

有没有人有一个简单的例子让 Java 可以使用协议和记录?

4

1 回答 1

6

defprotocol

每个 Clojure 协议也是一个具有相同名称和方法的 Java 接口。如果我以ibm developerworks为例,我们会看到:

(ns com.amalgamated)

(defprotocol Fulfillment
  (invoice [this] "Returns an invoice")
  (manifest [this] "Returns a shipping manifest"))

相当于:

package com.amalgamated;

public interface Fulfillment {
    public Object invoice();
    public Object manifest();
}

Clojure.org也有这方面的一些(相当简洁的)信息。

希望参与协议的 Java 客户端可以通过实现协议生成的接口最有效地做到这一点。可以使用扩展构造提供协议的外部实现(当您希望不在您的控制范围内的类或类型参与协议时需要):

(extend AType   AProtocol   
 {:foo an-existing-fn
    :bar (fn [a b] ...)
    :baz (fn ([a]...) ([a b] ...)...)}   BProtocol
    {...} ...)

definterface

如果你的目标是性能,你可以考虑使用definterface,它的使用类似于协议。此SO 帖子还包含有关如何使用它的详细信息:

(definterface Foo
  [^int foo [x ^String y]]
  [^void bar [^ints is]])

definterface似乎比协议更快。

defrecord

同样,records(以及deftypeand definterface)将生成 Java 类。同样,Clojure.org/datatypes有有用的信息(强调我的):

deftype 和defrecord为具有一组给定字段的命名类动态生成编译的字节码 ,并且可选地,为一个或多个协议和/或接口生成方法。它们适用于动态和交互式开发,不需要 AOT 编译,并且可以在单个会话过程中重新评估。它们在生成具有命名字段的数据结构方面类似于 defstruct,但与 defstruct 的不同之处在于:[...]

所以是的,如果可以从 Java 获得。只是要小心命名。

作为旁注,您可能想看看从 Java 调用 Clojure

于 2015-09-04T20:37:04.997 回答