読者です 読者をやめる 読者になる 読者になる

この日記は私的なものであり所属会社の見解とは無関係です。 GitHub: takahashikzn

メソッドがオーバーライドされたか否かを実行時に調べる

Java

例えばフックメソッドなど、オーバーライドされることで初めて意味を成すメソッドが有ります。


例えば、こんな感じ。onMethodメソッドとonFieldメソッドがそうです。

public class ClassInspector {


    public void inspect(Class<?> clazz) {

        for (Class<?> cls = clazz; Object.class != cls; cls = cls.gerSuperclass()) {
            for (Method m: cls.getMethods()) {
                onMethod(m);
            }

            for (Field f: cls.getFields()) {
                onField(f);
            }
        }

    }


    // オーバーライドして使うため,デフォルトは空実装
    protected void onMethod(Method m) {
    }

    // オーバーライドして使うため,デフォルトは空実装
    protected void onField(Field m) {
    }

}


このとき、ClassInspectorクラスを継承して作ったクラスがもしonMethodメソッドだけをオーバーライドしている場合、onFieldを呼び出すためのコードは実行しても無意味です。
しかもリフレクションは若干効率の悪い処理なので、できるだけ無駄は排除したい。さてどうするか。


そんな時は、こうするのが一番スマートだと思います。


public class SmarterClassInspector {

    private final boolean onMethodOverrided;
    private final boolean onFieldOverrided;

    protected SmarterClassInspector() {

        // 「現在のクラスにそれぞれのメソッドが実装されているか否か」=「オーバーライドしたか否か」
        try {
            getClass().getDeclaredMethod("onMethod", Method.class);
            onMethodOverrided = true;
        } catch (NoSuchMethodException e) {
            onMethodOverrided = false;
        } catch (Exception e) {
             throw new RuntimeException(e);
        }

        try {
            getClass().getDeclaredMethod("onField", Field.class);
            onFieldOverrided = true;
        } catch (NoSuchMethodException e) {
            onFieldOverrided = false;
        } catch (Exception e) {
             throw new RuntimeException(e);
        }
    }


    public void inspect(Class<?> clazz) {

        for (Class<?> cls = clazz; Object.class != cls; cls = cls.gerSuperclass()) {
            if (onMethodOverrided) {
                for (Method m: cls.getMethods()) {
                    onMethod(m);
                }
            }

            if (onFieldOverrided) {
                for (Field f: cls.getFields()) {
                    onField(f);
                }
            }
        }

    }


    // オーバーライドして使うため,デフォルトは空実装
    protected void onMethod(Method m) {
    }

    // オーバーライドして使うため,デフォルトは空実装
    protected void onField(Field m) {
    }

}


これで、オーバーライドされた時のみそれぞれのメソッドが実行されるようになります。