1

我开始更多地了解 Clojure-Java 互操作。如果我在 Clojure 中创建一个 Java 类,我需要导入它,但如果我只是使用类的字段或方法,我不必导入它。例如:

(ns students.Student
  (:import [sim.util Double2D])

(defn -step
  [this students]  ; students is a students.Students, extends sim.engine.SimState
  (let [yard (.-yard students) ; a sim.field.continuous.Continuous2D
        yard-width (.-width yard)
        yard-height (.-height yard)]
    (.setObjectLocation yard this (Double2D. (/ yard-height 2) (/ yard-width 2)))))

这不会在没有 import 的情况下编译Double2D,因为代码会创建一个Double2D实例。

但是,我访问实例的yard字段和setObjectLocation()方法以及Students实例的字段widthheight字段这一事实Continuous2D不会导致任何问题,即使我不导入StudentsContinuous2D类。

这是否意味着 Clojure 在运行时使用反射来访问 Java 字段和方法?那效率低吗?如果我需要函数的速度,是否可以为 Java 类添加类型声明以及缺少的导入语句?这会阻止反射吗?

[编辑:正如我对 Arthur Ulfeldt 回答的第二条评论所暗示的那样,我现在认为,由于在编译时不知道类而导致的任何低效率可能与函数包含在变量中这一事实所导致的低效率没有太大区别。如果我担心这一点,我会忘记 Clojure 和纯 Java 编程(也许),而不是尝试使用 Clojure 中的 Java 库。对我来说,一个我可以使用 Clojure 而不是 Java 的世界是一个更好的世界。]

4

1 回答 1

4

Import 仅用于制作它,因此您不必在每次要使用它时输入类的全名,包括它的包名。如果一个类在类路径上,你可以在任何地方用它的全名来调用它。如果您作为导入语句,您可以仅通过类名调用它,但只能从存在该导入的命名空间内调用。

我将从一个新项目开始,并添加一个在默认项目中显然没有使用的依赖项,在本例中是用于监视内容的 Riemann 客户端(这是一个很棒的程序,请查看)

lein new hello

并添加 dep

(defproject hello "0.1.0-SNAPSHOT"
  :description "FIXME: write description"
  :url "http://example.com/FIXME"
  :license {:name "Eclipse Public License"
            :url "http://www.eclipse.org/legal/epl-v10.html"}
  :aot :all
  :main hello.core
  :profiles {:uberjar {:aot :all}}
  :dependencies [[org.clojure/clojure "1.6.0"]
                 [com.aphyr/riemann-java-client "0.3.1"]])

然后第一件事,我将通过它的全名来查看那个类,而不需要任何导入

hello.core> com.aphyr.riemann.client.RiemannClient
com.aphyr.riemann.client.RiemannClient

然后尝试短名称:

hello.core> RiemannClient
CompilerException java.lang.RuntimeException: Unable to resolve symbol: RiemannClient in this context, compiling:(/tmp/form-init3055907211270530213.clj:1:5933) 

这不起作用:

hello.core> (import '[com.aphyr.riemann.client RiemannClient])
com.aphyr.riemann.client.RiemannClient

然后,如果我们添加导入并重试:

hello.core> RiemannClient
com.aphyr.riemann.client.RiemannClient

该名称从用户命名空间内解析。
如果我更改命名空间:

hello.core> (in-ns 'foo)

然后再看看这个类:

foo> RiemannClient
CompilerException java.lang.RuntimeException: Unable to resolve symbol: RiemannClient in this context, compiling:(/tmp/form-init3055907211270530213.clj:1:5933) 
foo> com.aphyr.riemann.client.RiemannClient
com.aphyr.riemann.client.RiemannClient

我们可以看到导入是每个命名空间的,尽管类路径上的类随处可用。

于 2015-04-24T22:21:16.090 回答