What's the best way to detect whether an object is a Java primitive array in Clojure?
检测对象是否是Clojure中的Java基元数组的最佳方法是什么?
The reason I need this is to do some special handling for primitive arrays, which might look something like:
我需要这样做的原因是对原始数组做一些特殊的处理,可能看起来像:
(if (byte-array? object)
(handle-byte-array object))
It's in a fairly performance-sensitive piece of code so I'd rather avoid reflection if at all possible.
它是一段性能敏感的代码,所以如果可能的话,我宁愿避免反射。
6 个解决方案
#1
8
you can use reflection once to get the class from the name, cache this and then compare the rest to that
您可以使用反射一次从名称中获取类,缓存这个,然后将其余的与那个进行比较
(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
#2
7
(defn primitive-array? [o]
(let [c (class o)]
(and (.isArray c)
(.. c getComponentType isPrimitive))))
For particular cases, you could use something like the following:
对于特殊情况,您可以使用以下内容:
(defn long-array? [o]
(let [c (class o)]
(and (.isArray c)
(identical? (.getComponentType c) Long/TYPE))))
#3
5
To check for a byte array without the use of reflection you can do this:
要在不使用反射的情况下检查字节数组,可以这样做:
(def ^:const byte-array-type (type (byte-array 0)))
(defn bytes? [x] (= (type x) byte-array-type))
Not exactly sure why, but you can even inline the byte-array-type with ^:const
.
不知道确切的原因,但是你甚至可以内联byte-array-type ^:常量。
#4
4
Or plain old instance?
:
或普通的旧实例吗?
(instance? (RT/classForName "[B") thing)
#5
4
As pointed by Arthur Ulfeldt, you can use Class/forName
, for example, like here:
正如Arthur Ulfeldt所指出的,您可以使用类/forName,例如:
(def byte_array_class (Class/forName "[B"))
(defn byte-array? [arr] (instance? byte_array_class arr))
If you want to avoid magic strings like "[B"
when caching the classes, you can apply class
to an existing array object:
如果您想要避免像“[B]”这样的魔法字符串,那么可以将类应用到现有的数组对象:
(def byte_array_class (class (byte-array [])))
#6
2
Props to all the other answers. Here it is as a one-liner:
所有其他答案的道具。这是一句俏皮话:
(def byte-array? (partial instance? (Class/forName "[B")))
For other primitives, refer to http://docs.oracle.com/javase/7/docs/api/java/lang/Class.html#getName%28%29 (or the java spec). Or just do what Gerrit suggests with (type (xyz-array 0))
. Specifically you can use:
对于其他原语,请参考http://docs.oracle.com/javase/7/docs/api/java/lang/Class.html#getName%28%29(或java规范)。或者按照Gerrit的建议(类型(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
Since performance was mentioned, here's a small benchmark result of running (time (dotimes [_ 500000] (byte-array? x)))
, and with byte-array-class
def'd
由于提到了性能,这里有一个运行的小基准结果(时间(dotimes[_ 500000])(字节数组?)和字节数组类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
= instance? wins
实例?vs类型=实例?赢了
partial
vs defn
= defn wins
部分vs
but any of these approaches will likely not be a bottleneck in performance.
但这些方法中的任何一种都可能不会成为性能的瓶颈。
#1
8
you can use reflection once to get the class from the name, cache this and then compare the rest to that
您可以使用反射一次从名称中获取类,缓存这个,然后将其余的与那个进行比较
(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
#2
7
(defn primitive-array? [o]
(let [c (class o)]
(and (.isArray c)
(.. c getComponentType isPrimitive))))
For particular cases, you could use something like the following:
对于特殊情况,您可以使用以下内容:
(defn long-array? [o]
(let [c (class o)]
(and (.isArray c)
(identical? (.getComponentType c) Long/TYPE))))
#3
5
To check for a byte array without the use of reflection you can do this:
要在不使用反射的情况下检查字节数组,可以这样做:
(def ^:const byte-array-type (type (byte-array 0)))
(defn bytes? [x] (= (type x) byte-array-type))
Not exactly sure why, but you can even inline the byte-array-type with ^:const
.
不知道确切的原因,但是你甚至可以内联byte-array-type ^:常量。
#4
4
Or plain old instance?
:
或普通的旧实例吗?
(instance? (RT/classForName "[B") thing)
#5
4
As pointed by Arthur Ulfeldt, you can use Class/forName
, for example, like here:
正如Arthur Ulfeldt所指出的,您可以使用类/forName,例如:
(def byte_array_class (Class/forName "[B"))
(defn byte-array? [arr] (instance? byte_array_class arr))
If you want to avoid magic strings like "[B"
when caching the classes, you can apply class
to an existing array object:
如果您想要避免像“[B]”这样的魔法字符串,那么可以将类应用到现有的数组对象:
(def byte_array_class (class (byte-array [])))
#6
2
Props to all the other answers. Here it is as a one-liner:
所有其他答案的道具。这是一句俏皮话:
(def byte-array? (partial instance? (Class/forName "[B")))
For other primitives, refer to http://docs.oracle.com/javase/7/docs/api/java/lang/Class.html#getName%28%29 (or the java spec). Or just do what Gerrit suggests with (type (xyz-array 0))
. Specifically you can use:
对于其他原语,请参考http://docs.oracle.com/javase/7/docs/api/java/lang/Class.html#getName%28%29(或java规范)。或者按照Gerrit的建议(类型(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
Since performance was mentioned, here's a small benchmark result of running (time (dotimes [_ 500000] (byte-array? x)))
, and with byte-array-class
def'd
由于提到了性能,这里有一个运行的小基准结果(时间(dotimes[_ 500000])(字节数组?)和字节数组类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
= instance? wins
实例?vs类型=实例?赢了
partial
vs defn
= defn wins
部分vs
but any of these approaches will likely not be a bottleneck in performance.
但这些方法中的任何一种都可能不会成为性能的瓶颈。