2013-01-04 63 views
2

說我有一個基類A(一個名爲normalInit()虛方法),以及300個小類:A1, A2, A3, ...每個子類有staticInit()靜態方法,再加上一個normalInit()覆蓋。 (請不要問爲什麼;這是在已經給出的生產軟件中,不能改變設計以便更好地重複使用,實際上,這些子類是由代碼生成器生成的,但現在這是不相關的。)從(超)子類的實例列表調用靜態方法

根據應用程序的不同執行情況,A1, A2, A3, ...的(小)子集需要初始化。換句話說,某些特定的Ai共享或訪問的所有實例都有一些數據。顯然,將這​​些實體定義爲static成員/方法(因爲它們由Ai的所有實例共享)是合理的。

那麼如何初始化該子集的靜態(並調用靜態方法)呢?簡而言之,這不是靜態初始化全部Ai子類的解決方案,因爲只需要一小部分子集(將浪費內存)。 Java中的static行爲顯然爲此提供了一個解決方案:類的初始化器在初次訪問時初始化(我在此忽略了一些特殊情況,例如,在這種情況下編譯器內聯最終靜態,從技術上來說,沒有課程訪問權限,只是在源代碼級別)。

的問題是,我需要確定性(實際上是在預定義的時間)靜態初始化,因爲他們的行爲static也可以訪問應用程序的當前靜態(全局)狀態。因此,static初始值設定項不是一個選項,我需要static方法,以在適當的位置顯式調用它們。

在有問題的應用程序中,必須在遍歷ArrayList<A>(其中A是超類)中訪問各種Ai類的實例時完成此操作。

for (int i = 0; i < list.size(); ++i) { 
     list[i].normalInit(args); // normalInit() is an instance method 
    } 

該列表由Ai實例(的A1例如950個實例中,A2 1750個實例等,在未排序的, 「隨機」 順序)。

換句話說,我不能訪問具體的類名(因此我不能只調用A4.staticInit()),因爲我不知道哪個Ai在列表中有實例。 注意,我知道靜態在編譯時綁定,我知道多態是不可能在這裏,所以我不問如何調用上述循環的靜態方法!當調用normalInit()時,由於動態調度,具體稱爲實例(以及因此它的Class)在運行時決定。

表觀溶液是調用具體類從normalInit()倍率staticInit()方法:

public class A2 { 

    @Override 
    public void normalInit(int[] args) { 
     // ...  

     staticInit(); 
    } 

    private static void staticInit() { 
      if (!sStaticInitialized) { 
       sStaticInitialized = true; 
       ... 
      } 
    } 
} 

對於這一點,該生成Ai小類中所述的代碼生成的模板必須進行修改。

但是,這(和上面的代碼)看起來不是一個很好的解決方案。我瞭解整體應用程序設計是否存在一些缺陷,但即使這是您的觀點,如果此類索賠增加了額外(獨立)建設性意見,我將不勝感激。上述問題是否有更好的解決方案/成語?

+2

您是否嘗試過反射?調用由類名定義的不同類的一個靜態方法作爲字符串... –

+0

這將是一個類似的解決方案(只是比現在慢),不是嗎?我仍然需要存儲哪些Ai類名已經通過反射訪問(調用它們的靜態方法)。 –

+0

使用反射,您可以直接訪問靜態方法,而不用包裝它。缺點是在迭代之前必須將類的名稱設置爲String []。 –

回答

2

好,使用反射回答是:

String classPrefixName = "com.your.company.A"; 
for (int i = 0; i< 300; i++) { 
    Class<?> clazz = Class.forName(classPrefixName+i); //look for the class 
    Method method = clazz.getDeclaredMethod("staticInit"); //look for the method 
    method.invoke(null); //invoke(null), since it's a static method 
} 

這樣,你不需要換一個實例一個內部的靜態方法。