16

我知道 clojure/java 互操作的基础知识:从 clojure 调用 java,反之亦然。但是,我无法将类型化集合从 clojure 返回到 java。我试图List<TypedObject>从调用clojure的java代码中看到这种性质的东西。

Java Object:

public class TypedObject {
    private OtherType1 _prop1;
    public OtherType1 getProp1() {
        return _prop1;
    }
    public void setProp1(OtherType1 prop1) {
        _prop1 = prop1;
    }
}

CLojure method:

(defn -createListOfTypedObjects
      "Creates and returns a list of TypedObjects"
      [input]
      ;Do work here  to create and return list of TypedObjects
      [typedObj1, typedObj2, typedObj3])

(:gen-class
 :name some.namespace
 :methods [createListofTypedObjects[String] ????])

让我们考虑一下我正在使用 clojure 编写一个 API,该 API 将作为 jar 文件分发,以便从 java 中使用。我的问题真的是如何通过什么来代替 ???? AOT 的 :gen-class 上面的问号,以便程序员使用我的 api 在 java 中编写一段代码,createListofTypedObjects() returns List<TypedObject>例如,可以从 eclipse 中获得适当的智能感知/代码完成(即:)。

4

3 回答 3

23

其他人说得对,Clojure 不保证返回集合中的元素类型等。(实际上,JVM 也不保证集合中元素的类型——这完全由 javac 处理。)

但是,我可以看到向其他 Java 程序员提供 API 的价值,该 API 指定一个接口,该接口声明以各种方式参数化的返回值(或参数);如果希望在现有的 Java 环境中使用 Clojure 而不会引起轰动,这将特别有吸引力。

这目前需要一个两步过程:

  • 定义一个单独的接口(在 Java 中!),根据需要指定参数化类型
  • 定义您的gen-class命名空间(或proxy实例reify),使其实现该接口

(Clojure 确实提供了一种definterface形式,可以让您避免单独的 Java 接口定义,但是definterface,就像 Clojure 的其余部分一样,不提供指定参数化类型。也许有一天...... :-))

例如

public interface IFoo {
    List<TypedObject> createListOfTypedObjects ();
}

然后是你的 gen-class 命名空间:

(ns your.ns.FooImpl
  (:gen-class
    :implements [IFoo]))
(defn -createListOfTypedObjects
  []
  [typedObj1, typedObj2, typedObj3])

当您的用户创建 的实例时FooImpl,他们将例如获得代码完成,指示该方法返回List<TypedObject>而不是返回Object未参数化的List类型。

如果您使用的是健全的构建工具(例如maven、gradle 或正确配置的 ant),那么您可以将 Java 接口放入您的 Clojure 项目中,并且跨语言依赖将得到处理。

于 2010-09-22T14:39:23.470 回答
10

如果您尝试将类似的东西传递List<String>给 java 方法,那么您无需担心它。类型参数(例如,String)仅由 javac 编译器使用,因此任何List在运行时都可以正常工作。

另一方面,如果您尝试传递特定对象类型的数组(例如,String[]),那么您可以使用各种-array函数:

user=> (make-array String 10)            ; an empty String array
#<String[] [Ljava.lang.String;@78878c4c>
user=> (into-array ["foo" "bar"])        ; array type inferred from first element
#<String[] [Ljava.lang.String;@743fbbfc>
user=> (into-array Number [1.2 5 7N])    ; explicit type array
#<Number[] [Ljava.lang.Number;@7433b121>
于 2010-09-11T01:12:20.663 回答
9

您无需担心 Clojure 中的泛型(类型化集合)。泛型实际上只是 Java 编译器的类型提示。在运行的 Java 程序中,List<String>实际上与List<Object>.

因此,例如,包含字符串的 Clojure 向量已经是List<String>不需要转换的。

于 2010-09-11T01:13:10.117 回答