пятница, 1 июля 2011 г.

Создание экземпляра класса по имени

Для создания экземпляра класс в clojure можно воспользоваться специальной формой new

(new String)
или более краткой записью '.'

(String.)
Но не всегда этих средств достаточно. Возникает необходимость создания объекта класса, зная только имя целевого класса(например хранящегося в виде строки "String"). В этом случае объект можно создать воспользовавшись методами java-классов java.lang.Class(для классов с конструктором без параметров) и java.lang.reflect.Constructor - для конструкторов с параметрами.
Первый шаг создания объекта по имени класса - это найти полное имя класса, решается с помощью функции ns-resolve. Поиск выполняется в текущем пространстве имен(*ns*)

(ns-resolve *ns* (symbol "String"))
java.lang.String
В случае успеха ns-resolve возвращает экземпляр класса java.lang.Class.

Если конструктор класса с параметрами, необходимо найти конструктор с подходящей сигнатурой(метод getConstructor класса java.lang.reflect.Constructor). И создать новый объект методом newInstance.
Окончательно функция будет выглядеть так:

(defn new-instance [name & args]
  (let [class (ns-resolve *ns* (symbol name))]
    (if (= java.lang.Class (type class))
      (if args
        (let [type-args (into-array java.lang.Class (map #(type %) args))]
          (.newInstance (.getConstructor class type-args) (into-array args)))
        (.newInstance class)))))
Пример использования

user=> (new-instance "String")
""
user=> (new-instance "String" "abc")
"abc"
user=> (type (new-instance "String" "123"))
java.lang.String




Комментариев нет:

Отправить комментарий