如何将类型化的集合从clojure传递给java?

use*_*030 16 java interop clojure aot

我知道clojure/java interop的基础知识:从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] ????])
Run Code Online (Sandbox Code Playgroud)

让我们考虑一下,我正在使用clojure编写一个API,它将作为jar文件分发,以便在java中使用.我的问题是如何通过代替???? 上面的问题标记在:AOT的gen类中,所以程序员使用我的api在java中编写一段代码,可以createListofTypedObjects() returns List<TypedObject>从eclipse中获得相应的intellisense/code completion(即:) .

cem*_*ick 20

其他是正确的,Clojure不能确保返回集合中的元素类型等.(实际上,JVM也不能确保集合中元素的类型 - 完全由javac处理.)

但是,我可以看到为其他Java程序员提供API的价值,这些程序员指定了一个接口,该接口声明以各种方式参数化的返回值(或参数); 如果想要在现有Java环境中使用Clojure而不产生波浪,这尤其具有吸引力.

这目前需要两个步骤:

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

(Clojure确实提供了一个definterface允许你避免单独的Java接口定义的表单,但是definterface,就像Clojure的其余部分一样,不提供指定参数化类型.也许有一天... :-))

例如

public interface IFoo {
    List<TypedObject> createListOfTypedObjects ();
}
Run Code Online (Sandbox Code Playgroud)

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

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

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

如果您正在使用理智的构建工具(例如maven,gradle或正确配置的ant),那么您可以将Java接口放在Clojure项目中,并且将考虑跨语言依赖性.


Ale*_*art 11

如果你试图将类似的东西传递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>
Run Code Online (Sandbox Code Playgroud)


Stu*_*rra 10

您不必担心Clojure中的泛型(类型集合).泛型实际上只是Java编译器的类型提示.在一个正在运行的Java程序中,List<String>实际上是一样的List<Object>.

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

  • 不对。更准确地说,您_通常_不需要担心 Clojure 中的类型化集合。由于这个问题专门涉及 Java 互操作,因此必须指出给定集合可能在某个时刻被传递回 Java 方法。在这种情况下,如果方法名称重载并采用具有不同元素类型的集合,则集合中元素的类型可能很重要。我知道这可能很晦涩且不常见......但它确实存在。 (2认同)