Если я знаю имя класса объекта, как получить его и вызвать его метод? - PullRequest
1 голос
/ 07 марта 2011

У меня есть черта, названная Init:

package test
trait Init {
    def init(): Any
}

Есть некоторые классы и объект, расширяющий эту черту:

package test
object Config extends Init {
    def init() = { loadFromFile(...) }
}
class InitDb extends Init {
    def init() = { initdb() }
}

Когда приложение запустится, я будунайдите все классы и объекты, расширяющие Init, и вызовите их метод init.

package test
object App {
    def main(args: Array[String]) {
        val classNames: List[String] = findAllNamesOfSubclassOf[Init]
        println(classNames) // -> List(test.Config$, test.InitDb)
        classNames foreach { name =>
             Class.forName(name).newInstance().asInstanceOf[Init].init() // ***
        }
    }
}

Обратите внимание на строку "*".Для test.InitDb все нормально.Но для test.Config$, когда newInstance(), он выдает исключение, сказав, что мы не можем получить доступ к его закрытому методу.

Моя проблема в том, как получить этот объект и запустить его метод init?

Ответы [ 2 ]

6 голосов
/ 07 марта 2011

Обычно в Scala делать это бессмысленно.Просто поместите некоторый код в тело любого object, и он будет выполнен при первой инициализации этого объекта, что избавит вас от неприятного удара по производительности, связанного с предварительной инициализацией всего.

В общем, поиск всех подклассовопределенного типа требует полного сканирования пути к классам.Для этого есть несколько библиотек, но одна из наиболее распространенных - это Apache commons-Discover

Однако ... Это динамический код, он использует отражение, и он действительно НЕ идиоматичен,У Scala есть более острые инструменты, поэтому, пожалуйста, не пытайтесь швырять тупых с таким насилием!

0 голосов
/ 02 марта 2012

Я не совсем согласен с Кевином. Есть несколько исключений. Например, я написал настольное приложение Scala. Я разделил ядро ​​и модули на две части. Во время запуска ядро ​​загружает все модули в графический интерфейс. В то время ядро ​​просто получает имена модулей, ему не нужно что-то инициализировать. Затем я поместил код инициализации всего модуля в функцию init(). Эта функция будет вызвана, когда пользователь выполнит модуль.

@ Freewind: Что касается отражения в Scala, то же самое в Java. Просто обратите внимание, что методы из Java, которые используются с отражением, используются для объектов Java, а не Scala. Я извиняюсь за мой английский. Я имею в виду, что эти методы не могут работать с Scala object, trait.

Например:

var classLoader = new java.net.URLClassLoader(
    Array(new File("module.jar").toURI.toURL),
    /*
     * need to specify parent, so we have all class instances
     * in current context
     */
    this.getClass.getClassLoader)

var clazz = classLoader.loadClass("test.InitDb")
if (classOf[Init].isAssignableFrom(clazz))
    var an_init = clazz.newInstance.asInstanceOf[Init];

Но вы не можете сделать это наоборот:

if (clazz.isAssignableFrom(classOf[Init]))

Поскольку Init является trait, а метод Java isAssignableFrom(Class) не знает trait.

Я не уверен, что мой вопрос полезен для вас, но здесь это .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...