2011-03-07 58 views
1

我有一個特點,命名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方法?

回答

6

在Scala中這樣做通常沒什麼意義。只需在任何object的主體中添加一些代碼,並在該對象首次初始化時執行,從而爲您節省預初始化所有內容時令人討厭的性能。

一般來說,查找特定類型的所有子類都需要完整的類路徑掃描。有幾個庫可以做到這一點,但其中一個更常見的是Apache's commons-discover

但是...這是動態代碼,它使用了反射,它實際上不是慣用的。斯卡拉的工具比那個更鋒利,所以請不要試圖用這種暴力來擺動鈍器!

+0

謝謝。我試圖將一些啓動代碼放入webapp的某些對象中,但是當jetty啓動時,我發現它們沒有被執行,因爲沒有其他類需要它們。但是我需要在碼頭啓動時執行它們,而不管其他類是否可以訪問它們。如何做?我的解決方案是讓他們擴展'Init',並找到並調用它們作爲我的例子。你能給我更多的建議嗎? – Freewind 2011-03-07 12:48:25

+0

將所有代碼放在專用啓動servlet中,或者使用您的Web框架提供的任何等效機制。如果這些單身人士沒有在其他地方實際使用過,那麼你真的想問你爲什麼要首先定義他們...... – 2011-03-07 12:58:39

+0

謝謝。我現在使用'ServletContextListener'來執行此操作 – Freewind 2011-03-07 13:19:07

0

我不完全同意凱文。有一些例外。例如,我寫了一個Scala桌面應用程序。我將核心和模塊分成兩部分。在啓動時,核心將所有模塊加載到GUI中。那時核心只是獲得模塊的名稱,它不需要初始化一些東西。然後我把所有模塊的init代碼放在一個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])) 

因爲Inittrait,而Java方法isAssignableFrom(Class)不知道trait

我不確定我的問題對您有用,但是here it is

相關問題