在Clojure中动态访问Java字段?

9

我是一个Clojure和Java的新手。

为了在Clojure中访问Java字段,您可以执行以下操作:

Classname/staticField

这与

是完全相同的
(. Classname staticField)

(如果我错了,请纠正我)

当静态字段的名称保存在变量中时,如何访问该字段? 例如:

(let [key-stroke 'VK_L
      key-event KeyEvent/key-stroke])

我希望在访问该字段之前,key-stroke 能够被解析为符号 VK_L。


3
除了skuro的回答外,您还可以查看Java反射API。请参阅http://java.sun.com/developer/technicalArticles/ALT/Reflection/中的“更改字段的值”部分。 - gatoatigrado
再解释一下:字段或方法调用的访问必须在字节码中编译。这就是为什么您无法使用运行时信息构造它们的原因。如果您需要这样做,您将不得不使用反射。(请参见Joost的答案) - kotarak
4个回答

10
在这种情况下,你可能想要执行类似以下的操作:
user=> (def m 'parseInt)          
#'user/m
user=> `(. Integer ~m "10")       
(. java.lang.Integer parseInt "10")
user=> (eval `(. Integer ~m "10"))
10

如果你感觉这样做有点像黑客式的,那是因为它确实是这样。可能有更好的代码结构方式,但至少这个应该可以工作。


这个回答对您有帮助吗?愿意接受它(或任何其他人的回答)吗? - skuro

7

我做了一个小的Clojure库,使用反射API将公共字段转换为Clojure映射:

(ns your.namespace
 (:use nl.zeekat.java.fields))

(deftype TestType
    [field1 field2])

; fully dynamic:

(fields (TestType. 1 2)) 
=> {:field1 1 :field2 2}

; optimized for specific class:
(def-fields rec-map TestType)

(rec-map (TestType. 1 2)) 
=> {:field1 1 :field2 2}

请查看https://github.com/joodie/clj-java-fields

5

反射可能是正确的方法,但最简单的方式是

(eval (read-string (str "KeyEvent/" key-stroke)))

这只是将生成的字符串转换为有效的Clojure,然后进行评估。


1

您可以将正确的调用构造为s表达式,并按以下方式进行评估:

(let [key-stroke 'VK_L
      key-event (eval `(. KeyEvent ~key-stroke))]
  ....do things with your key-event......)

然而,如果你想要测试某个按键是否被按下,你可能不需要这些:我通常发现编写类似以下代码最容易:

(cond
  (= KeyEvent/VK_L key-value) 
    "Handle L"
  (= KeyEvent/VK_M key-value) 
    "Handle M"
  :else
    "Handle some other key")

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接