如何将类型化的集合从clojure传递给java?
我知道clojure / java interop的基础知识:从clojure调用java,反之亦然。 但是,我无法将clojure中的类型集合返回到java。 我试图从调用clojure的java代码中看到一些自然的List
。
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,它将作为jar文件分发,以便在java中使用。 我的问题是如何通过代替???? 上面的问题标记在:AOT的gen-class中,以便程序员使用我的api在java中编写一段代码,可以从eclipse中获得相应的intellisense / code completion(即: createListofTypedObjects() returns List
)例如。
其他正确的是Clojure不能确保返回集合中的元素类型等。(实际上,JVM也不能确保集合中元素的类型 – 完全由javac处理。)
但是,我可以看到为其他Java程序员提供API的价值,这些程序员指定了一个接口,该接口声明以各种方式参数化的返回值(或参数); 如果想要在现有的Java环境中使用Clojure而不产生波浪,这一点尤其具有吸引力。
这目前需要两个步骤:
- 定义一个单独的接口(在Java中!),它可以根据需要指定参数化类型
- 定义您的
gen-class
命名空间(或proxy
或reify
实例),以便它实现该接口
(Clojure确实提供了一个允许你避免单独的Java接口定义的definterface
forms,但是definterface
,就像Clojure的其余部分一样,没有提供指定参数化类型。也许有一天… :-))
例如
public interface IFoo { List createListOfTypedObjects (); }
然后你的gen-class命名空间:
(ns your.ns.FooImpl (:gen-class :implements [IFoo])) (defn -createListOfTypedObjects [] [typedObj1, typedObj2, typedObj3])
当您的用户创建FooImpl
实例时,他们将获得代码完成,表明该方法返回List
而不是Object
或未参数化的List
类型。
如果您正在使用理智的构建工具(例如maven ,gradle或正确配置的ant),那么您可以将Java接口放在Clojure项目中,并且将考虑跨语言依赖性。
如果您尝试将类似List
传递给java方法,那么您不必担心它。 类型参数(例如, String
)仅用于javac编译器,因此任何List
在运行时都可以正常工作。
另一方面,如果您尝试传递特定对象类型的数组(例如, String[]
),那么您可以使用各种-array
函数:
user=> (make-array String 10) ; an empty String array # user=> (into-array ["foo" "bar"]) ; array type inferred from first element # user=> (into-array Number [1.2 5 7N]) ; explicit type array #
您不必担心Clojure中的generics(类型集合)。 generics实际上只是Java编译器的类型提示。 在正在运行的Java程序中, List
实际上与List
相同。
因此,例如,包含字符串的Clojure向量已经是List
,不需要转换。