在Clojure中检测对象是否是Java原始数组的最佳方法是什么?
我需要这个的原因是对原始数组做一些特殊的处理,它可能看起来像:
(if (byte-array? object)
(handle-byte-array object))
这是一段性能相当敏感的代码,所以我宁愿尽量避免反思。
答案 0 :(得分:9)
你可以使用反射一次从名称中获取类,然后缓存它 比较其余的
(def array-of-ints-type (Class/forName "[I"))
(def array-of-bytes-type (Class/forName "[B"))
...
(= (type (into-array Integer/TYPE [1 3 4])) array-of-ints-type)
true
答案 1 :(得分:7)
(defn primitive-array? [o]
(let [c (class o)]
(and (.isArray c)
(.. c getComponentType isPrimitive))))
对于特定情况,您可以使用以下内容:
(defn long-array? [o]
(let [c (class o)]
(and (.isArray c)
(identical? (.getComponentType c) Long/TYPE))))
答案 2 :(得分:6)
要在不使用反射的情况下检查字节数组,可以执行以下操作:
(def ^:const byte-array-type (type (byte-array 0)))
(defn bytes? [x] (= (type x) byte-array-type))
不完全确定原因,但您甚至可以使用^:const
内联字节数组类型。
答案 3 :(得分:5)
正如Arthur Ulfeldt指出的那样,你可以使用Class/forName
,例如,像这里:
(def byte_array_class (Class/forName "[B"))
(defn byte-array? [arr] (instance? byte_array_class arr))
如果要在缓存类时避免使用"[B"
之类的魔术字符串,可以将class
应用于现有数组对象:
(def byte_array_class (class (byte-array [])))
答案 4 :(得分:4)
或普通的instance?
:
(instance? (RT/classForName "[B") thing)
答案 5 :(得分:3)
支持所有其他答案。这是一个单行:
(def byte-array? (partial instance? (Class/forName "[B")))
对于其他原语,请参阅http://docs.oracle.com/javase/7/docs/api/java/lang/Class.html#getName%28%29(或java规范)。或者只是做Gerrit对(type (xyz-array 0))
的建议。具体来说,您可以使用:
"[Z" boolean array
"[B" byte array
"[C" char array
"[D" double array
"[F" float array
"[I" integer array
"[J" long array
"[S" short array
由于提到了效果,这是运行(time (dotimes [_ 500000] (byte-array? x)))
和byte-array-class
def' d
(def byte-array? (partial instance? (Class/forName "[B")))
78.518335 msecs
(defn byte-array? [obj] (instance? byte-array-class obj))
34.879537 msecs
(defn byte-array? [obj] (= (type obj) byte-array-class))
49.68781 msecs
instance?
vs type
=实例?胜
partial
vs defn
= defn wins
但这些方法中的任何一种都可能不会成为性能瓶颈。
答案 6 :(得分:0)
从Clojure 1.9开始,您可以使用bytes?
bytes? doc link