2

基本クラスA(仮想メソッドと呼ばれるnormalInit())と300個のサブクラスがあるとします。A1, A2, A3, ...これらの各サブクラスにはstaticInit()静的メソッドとnormalInit()オーバーライドがあります。(理由を聞かないでください。これはすでに提供されている実稼働ソフトウェアであり、再利用を改善するために設計を変更することはできません。実際、これらのサブクラスはコードジェネレーターによって生成されますが、現在は関係ありません。)

アプリケーションのさまざまな実行に応じて、の(小さな)サブセットをA1, A2, A3, ...初期化する必要があります。つまり、特定のすべてのインスタンスがAi共通に共有またはアクセスするデータがいくつかあります。明らかに、これらのエンティティをstaticメンバー/メソッドとして定義および処理することは合理的です(これらはのすべてのインスタンスで共有されるためAi)。

では、このサブセットの静的メソッドを初期化する(そして静的メソッドを呼び出す)方法は?

簡単に言うと、必要なサブセットはごくわずかであるため(メモリの浪費になるため)、すべてのサブクラスを静的に初期化することは解決策ではありません。 AiJavaでのstatic動作は、明らかにこれに対する解決策を提供します。クラスのstatic初期化子は、クラスに初めてアクセスしたときに初期化されます(ここでは、いくつかの特殊なケースを無視します。クラスアクセスではなく、ソースコードレベルでのみです)。

問題は、それらの動作がアプリケーションの現在の静的(グローバル)状態にもアクセスするため、決定論的(実際には事前定義された時間)の静的初期化が必要なことです。staticしたがってstatic、初期化子はオプションではありませんstatic。適切な場所で明示的に呼び出すためのメソッドが必要です。

問題のアプリケーションでは、これは、スーパークラスである、Aiを介した反復によってさまざまなクラスのインスタンスにアクセスするときに実行する必要があります。ArrayList<A>A

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

このリストはAiインスタンスで構成されます(たとえば、950個のインスタンスA1、1750個のインスタンスA2など、並べ替えられていない「ランダムな」順序で)。

つまり、リストにインスタンスが含まれているのがA4.staticInit()わからないため、具体的なクラス名にアクセスできません(したがって、単に呼び出すことはできません)。静的メソッドはコンパイル時にバインドされ、ここではポリモーフィズムが不可能であることを知っているので、上記のループから静的メソッドを呼び出す方法を尋ねていないことに注意してください。具体的に呼び出されるインスタンス(およびそのインスタンス)は、動的ディスパッチにより、が呼び出されるときに実行時に決定されます。AiClassnormalInit()

明らかな解決策は、オーバーライドから具象クラスのstaticInit()メソッドを呼び出すことです。normalInit()

public class A2 {   

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

        staticInit();
    }

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

このためには、Aiサブクラスを生成するコードジェネレーターテンプレートを変更する必要があります。

しかし、これ(および上記のコード)は良い解決策のようには見えません。アプリ全体のデザインに多少の欠陥があるかどうかはわかりますが、それがあなたの視点であっても、そのような主張が追加の(独立した)建設的なアドバイスで補強されれば幸いです。上記の問題に対するより良い解決策/イディオムはありますか?

4

1 に答える 1

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
}

そうすれば、静的メソッドをインスタンス内にラップする必要がなくなります。

于 2013-01-04T18:34:32.490 に答える