4

我试图将句柄放在编译时不可用但在运行时可用的 Java 对象上,如下所示:

(def component-manager (delay (SomeJavaObject/getHandle)))

(如果有比延迟更好的机制可用,这将是受欢迎的)。

使用这些对象时,会生成反射警告。由于有时这些相当频繁,我试图通过以下方式避免它:

(def my-handle ^SomeJavaObject (delay (SomeJavaObject/getHandle)))

不幸的是,在这种情况下仍然会产生反射警告。


修改参考作品:

(.foo ^SomeJavaObject @my-handle)

...但这大大丑化了代码。


包装在添加类型提示的宏中似乎是一种明显的方法:

(def my-handle' (delay (SomeJavaObject/getHandle)))
(defmacro my-handle []
  (with-meta '(deref my-handle')
             {:tag SomeJavaObject}))

...看起来它应该做正确的事情:

=> (set! *print-meta* true)
=> (macroexpand '(my-handle))
^SomeJavaObject (deref my-handle')

...但是当橡胶上路时,这并不成立:

=> (.foo (my-handle))
Reflection warning, NO_SOURCE_PATH:1 - reference to field foo can't be resolved.

这样做的正确方法是什么?

4

2 回答 2

3

我不确定延迟是否是最好的选择,或者是否有更好的解决方案来管理这些 Java 对象,但就反射警告而言,下面的代码确实通过将延迟值访问包装在具有类型提示的函数中来解决它。

user=> (set! *warn-on-reflection* true)
true
user=> (def myobj (delay "hello world"))
#'user/myobj
user=> (defn ^String get-my-obj [] @myobj)
#'user/get-my-obj
user=> (.length (get-my-obj))
11

为了使它更容易,您可以创建一个创建延迟对象的宏,还可以创建一个get-<delay object name>函数来使用类型提示访问该延迟对象。

于 2012-06-05T04:28:43.690 回答
2

我想提供两种不同的解决方案:

1.延迟

首先,我想发布一个答案,说明如何重现您的问题。(正如措辞,您的问题是抽象的,不能在 REPL 中运行。)

(set! *warn-on-reflection* true)
(def rt (delay (Runtime/getRuntime)))
(.availableProcessors @rt) ; Reflection warning

您提到您不喜欢以下方法,因为您认为它很冗长:

(.availableProcessors ^java.lang.Runtime @rt) ; no warning

我尝试了以下方法,但没有解决反射警告:

(def rt (delay ^java.lang.Runtime (Runtime/getRuntime)))
(.availableProcessors @rt) ; Reflection warning

结论:如果您想使用延迟,Ankur 的回答效果很好。为了适应这个例子:

(def delayed-runtime (delay (Runtime/getRuntime)))
(defn ^java.lang.Runtime get-runtime [] @delayed-runtime)
(.availableProcessors (get-runtime)) ; no warning

2. 记忆

你也可以考虑使用 memoization,因为它需要更少的代码:

(def ^java.lang.Runtime get-runtime (memoize #(Runtime/getRuntime)))
(.availableProcessors (get-runtime)) ; no warning
于 2014-03-01T00:20:34.420 回答