0

我在这里学习教程:https ://www.baeldung.com/java-method-handles

在clojure中,我有一个简单的例子:

(import (java.lang.invoke MethodHandles
                          MethodHandles$Lookup
                          MethodType
                          MethodHandle))

(defonce +lookup+ (MethodHandles/lookup))

(def ^MethodHandle concat-handle (.findVirtual +lookup+
                                 String
                                 "concat"
                                 (MethodType/methodType String String)))

(.invokeExact concat-handle (into-array Object ["hello" "there"]))

这给出了一个错误:

Unhandled java.lang.invoke.WrongMethodTypeException
 expected (String,String)String but found (Object[])Object

         Invokers.java:  476  java.lang.invoke.Invokers/newWrongMethodTypeException
         Invokers.java:  485  java.lang.invoke.Invokers/checkExactType
                  REPL:   26  hara.object.handle/eval17501
                  REPL:   26  hara.object.handle/eval17501
         Compiler.java: 7062  clojure.lang.Compiler/eval
         Compiler.java: 7025  clojure.lang.Compiler/eval
              core.clj: 3206  clojure.core/eval
              core.clj: 3202  clojure.core/eval
              main.clj:  243  clojure.main/repl/read-eval-print/f

有没有办法开始invoke工作?

4

2 回答 2

4

您可以使用.invokeWithArgumentswhich 将从提供的参数中找出正确的数量:

(.invokeWithArguments concat-handle (object-array ["hello" "there"]))
=> "hellothere"

或者您可以使用.invoke,但您需要MethodHandle.asSpreader正确应用String.concat具有固定数量的可变参数:

(def ^MethodHandle other-handle
  (.asSpreader
    concat-handle
    (Class/forName "[Ljava.lang.String;") ;; String[].class
    2))

(.invoke other-handle (into-array String ["hello" "there"]))
=> "hellothere"

.invokeExact如果可能的话,我不确定如何使用 Clojure 进行这项工作。

invokeExact 调用点的符号类型描述符必须与此方法句柄的类型完全匹配。不允许对参数或返回值进行转换。

这个答案.invoke对和的限制有更多解释.invokeExact

于 2018-09-18T03:50:39.957 回答
1

基于@TaylorWood 的回答的一些有趣的基准测试:

(with-out-str
  (time (dotimes [i 1000000]
          (.concat "hello" "there"))))
=> "\"Elapsed time: 8.542214 msecs\"\n"


(with-out-str
  (def concat-fn (fn [a b] (.concat a b)))
  (time (dotimes [i 1000000]
          (concat-fn "hello" "there"))))
=> "\"Elapsed time: 3600.357352 msecs\"\n"

(with-out-str
  (def concat-anno (fn [^String a b] (.concat a b)))
  (time (dotimes [i 1000000]
          (concat-anno "hello" "there"))))
=> "\"Elapsed time: 16.461237 msecs\"\n"

(with-out-str
  (def concat-reflect (.? String "concat" :#))
  (time (dotimes [i 1000000]
          (concat-reflect "hello" "there"))))
=> "\"Elapsed time: 1804.522226 msecs\"\n"

(with-out-str
  (def ^MethodHandle concat-handle
    (.findVirtual +lookup+
                  String
                  "concat"
                  (MethodType/methodType String String)))
  (time (dotimes [i 1000000]
          (.invokeWithArguments concat-handle (into-array Object ["hello" "there"])))))
=> "\"Elapsed time: 1974.824815 msecs\"\n" 

(with-out-str
  (def ^MethodHandle concat-spread
    (.asSpreader concat-handle
                 (Class/forName "[Ljava.lang.String;") ;; String[].class
                 2))
  (time (dotimes [i 1000000]
          (.invoke other-handle (into-array String ["hello" "there"])))))
=> "\"Elapsed time: 399.779913 msecs\"\n"
于 2018-09-18T05:27:50.463 回答