代码之家  ›  专栏  ›  技术社区  ›  Joe Holloway

如何将“静态最终”常数从Java类拉到Culjure命名空间?

  •  7
  • Joe Holloway  · 技术社区  · 15 年前

    我试图用一个CuljEube绑定包装一个Java库。Java库中的一个特定类定义了一组静态最终常数,例如:

    class Foo {
        public static final int BAR = 0;
        public static final int SOME_CONSTANT = 1;
        ...
    }
    

    我曾想过可以检查类并将这些常量拉入clojure名称空间,而不必显式地 def -每一个。

    例如,不要像这样显式地连接:

    (def foo-bar Foo/BAR)
    (def foo-some-constant Foo/SOME_CONSTANT)
    

    我可以检查 Foo 类和动态连接 foo-bar foo-some-constant 在加载模块时在我的clojure命名空间中。

    我认为这样做有两个原因:

    a)将新常数添加到 班级。换句话说,在Java接口添加了一个新的常量的情况下,我不必修改我的Culjress包装器。

    b)我可以保证常量遵循更为clojure式的命名约定

    我并不是真的这样做,但我想问一下,扩展我的Java / Java互操作性知识似乎是个好问题。

    谢谢

    3 回复  |  直到 15 年前
        1
  •  3
  •   Jürgen Hötzel    15 年前

    不幸的是宏 clojure.contrib.import-static公司 不允许导入 全部的 静态最终字段。必须提供要导入的字段列表。

    这个宏是 导入静态 :

    (ns stackoverflow
      (:use clojure.contrib.import-static)
      (:import (java.lang.reflect Modifier)))
    
    (defmacro import-static-fields
      "Imports all static final fields of the class as (private) symbols
      in the current namespace.
    
      Example: 
          user> (import-static-fields java.lang.Integer)
          #'user/TYPE
          user> MAX_VALUE
          2147483647
    
      Note: The class name must be fully qualified, even if it has already
      been imported."
      [class]
      (let [final-static-field? (fn [field]
                      (let [modifiers (.getModifiers field)]
                    (and (Modifier/isStatic modifiers) (Modifier/isFinal modifiers))))
        static-fields (map #(.getName %)
                   (filter
                    final-static-field?
                    (.. Class (forName (str class)) getFields)))]
        `(import-static ~class ~@static-fields)))
    
        2
  •  2
  •   Michał Marczyk    15 年前

    (这个答案现在包括两个可行的解决方案,一个基于我最初的想法 intern 一个是根据丹蕾的建议 c.c.import-static . 我想我需要晚一点把它清理干净,但我现在不能花更多的时间在它上…)

    要提取静态字段:

    (filter #(bit-and java.lang.reflect.Modifier/STATIC (.getModifiers %))
            (.getFields YourClass))
    

    然后映射 #(intern *ns* (str "a-prefix-" (.getName %)) (.get YourClass nil)) 通过这个序列来获得这个值…注意 此位未经测试 尤其是,我不确定 nil 在里面 .get ;实验 java.lang.Field 看看你的课上有什么用。

    更新2:

    好吧,事实上 实习生 基于方法的可读性并没有那么差:

    user> (map #(intern *ns* (symbol (str "integer-" (.getName %))) (.get % java.lang.Integer))
               (filter #(bit-and java.lang.reflect.Modifier/STATIC
                                 (.getModifiers %))
                       (.getFields java.lang.Integer)))
    (#'user/integer-MIN_VALUE #'user/integer-MAX_VALUE #'user/integer-TYPE #'user/integer-SIZE)
    user> integer-MIN_VALUE
    -2147483648
    user> integer-MAX_VALUE
    2147483647
    user> integer-TYPE
    int
    user> integer-SIZE
    32
    

    更新: (保留第一次更新作为替代解决方案)

    结合丹蕾的知识 clojure.contrib 在上述情况下,产生以下结果:

    user> (map #(eval `(import-static java.lang.Integer ~(symbol (.getName %))))
               (filter #(bit-and java.lang.reflect.Modifier/STATIC
                                 (.getModifiers %))
                       (.getFields java.lang.Integer)))
    (#'user/MIN_VALUE #'user/MAX_VALUE #'user/TYPE #'user/SIZE)
    user> MIN_VALUE
    -2147483648
    user> MAX_VALUE
    2147483647
    user> TYPE
    int
    user> SIZE
    32
    

    它使用 eval …好吧,那又怎样,它几乎不会“扼杀性能”,而且它实际上是相当可读的,一个精心设计的表达式使用 实习生 可能不是。 (其实没那么糟……-) 如果你愿意 实习生 不过,至少 import-static 如果我上面的素描不正确,可以给你一些正确的想法。

        3
  •  1
  •   danlei    15 年前

    我还没试过,但也许clojure.contrib.import-static可以做到。

    刚刚选中:在使用import static时,您必须命名方法/字段,但我将把这个答案留在这里,因为它可能有助于人们搜索相关的答案。