如果我知道一个对象的类名,如何获取它并调用它的方法?

发布于 2024-10-20 19:19:10 字数 909 浏览 1 评论 0原文

我有一个特征,名为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 方法?

I have a trait, named Init:

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

There are some classes and an object, extends this trait:

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

When app has started, I will find all classes and objects which extends Init, and invoke their init method.

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() // ***
        }
    }
}

Please note the "*" line. For test.InitDb, it's OK. But for test.Config$, when newInstance(), it throws an exception said we can't access its private method.

My problem is, how to get that object, and run its init method?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

赤濁 2024-10-27 19:19:10

在 Scala 中这样做通常没有什么意义。只需将一些代码放入任何对象的主体中,它就会在该对象首次初始化时执行,从而节省了预初始化所有内容所带来的令人讨厌的性能损失。

但一般来说,查找特定类型的所有子类需要完整的类路径扫描。有几个库可以做到这一点,但最常见的一个是 Apache 的 commons-discover< /a>

然而...这是动态代码,它使用反射,而且它确实不符合习惯。 Scala 有比这更锋利的工具,所以请不要尝试使用如此暴力的钝器!

There's usually little point to doing this in Scala. Just put some code in the body of any object and it'll be executed when that object is first initialised, saving you the nasty performance hit of pre-initialising everything.

In general though, finding all subclasses of a particular type requires a full classpath scan. There are a few libraries to do this, but one of the more common is Apache's commons-discover

However... This is dynamic code, it uses reflection, and it's really NOT idiomatic. Scala has sharper tools than that, so please don't try and swing the blunt ones with such violence!

御弟哥哥 2024-10-27 19:19:10

我不完全同意凯文的观点。但也有一些例外。例如,我编写了一个 Scala 桌面应用程序。我将核心和模块分成两部分。在启动时,核心将所有模块加载到 GUI 中。此时核心只获取模块的名称,不需要初始化某些东西。然后我将所有模块的初始化代码放入 init() 函数中。当用户执行该模块时将调用该函数。

@Freewind:关于Scala中的反射,在Java中是完全一样的。请注意,与反射一起使用的 Java 方法用于 Java 对象,而不是 Scala。我为我的英语感到抱歉。我的意思是这些方法不能与 Scala objecttrait 一起使用。

例如:

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)< /code>不知道特质

我不确定我的问题对您是否有用,但就在这里

I don't totally agree with Kevin. There are some exceptions. For example I wrote a Scala desktop app. I split the core and the modules into two parts. At startup time the core loads all modules into GUI. At that time the core just gets the name of modules, it doesn't need to initialize something. Then I put all module's init code in an init() function. That function will be called when user executes the module.

@Freewind: About reflection in Scala, it's absolutely the same in Java. Just please note that the methods from Java which are used with reflection, are used for Java objects - not Scala. I'm sorry for my English. I mean those methods can not work with Scala object, trait.

For example:

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];

But you can not do it the opposite way:

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

Because Init is a trait, and Java method isAssignableFrom(Class) doesn't know trait.

I'm not sure if my question is useful for you, but here it is.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文