2

親クラスで定義されたメソッドにアクセスするには? ここに、次の継承があります。

BaseDTO
|
SortableDTO<T>
|
BaseSearchArticleDTO
|
SearchNeedsYearPlus2ArticleDTO

メソッドpublic void setSortCriteria1(SortDataBean<T> sortCriteria1)は で定義されていSortableDTO<T>ます。クラスの参照を介してこのメ​​ソッドにアクセスしようとすると、次のSearchNeedsYearPlus2ArticleDTOようになります。

SearchNeedsYearPlus2ArticleDTO dto = new SearchNeedsYearPlus2ArticleDTO();
Method setSortCriteria1 = dto.getClass().getDeclaredMethod("setSortCriteria1",SortDataBean.class);

私は得ています:

java.lang.NoSuchMethodException: com.mhis.posm.web.dto.article.search.SearchNeedsYearPlus2ArticleDTO.setSortCriteria1(com.mhis.posm.transversal.bean.sort.SortDataBean)

しかし、私がこれを行うと:

Method setSortCriteria1 = dto.getClass().getSuperclass().getSuperclass().getDeclaredMethod("setSortCriteria1",SortDataBean.class);

それは働いています。それから私は自分がやっていることの間違いを見つけました。

Class#getDeclaredMethod:

この Class オブジェクトによって表されるクラスまたはインターフェイスの指定された宣言済みメソッドを反映する Method オブジェクトを返します。name パラメーターは、目的のメソッドの単純な名前を指定する String であり、 parameterTypes パラメーターは、宣言された順序でメソッドの仮パラメーターの型を識別する Class オブジェクトの配列です。同じパラメーター型を持つ複数のメソッドがクラスで宣言され、これらのメソッドの 1 つが他のどのメソッドよりも具体的な戻り値の型を持つ場合、そのメソッドが返されます。それ以外の場合は、いずれかの方法が任意に選択されます。名前が「<init>」または「<clinit>」の場合、NoSuchMethodException が発生します。

Class#getMethod

この Class オブジェクトによって表されるクラスまたはインターフェイスの指定されたパブリック メンバー メソッドを反映する Method オブジェクトを返します。name パラメータは、目的のメソッドの単純な名前を指定する文字列です。parameterTypes パラメーターは、宣言された順序でメソッドの仮パラメーターの型を識別する Class オブジェクトの配列です。parameterTypes が null の場合、空の配列であるかのように扱われます。

名前が「<init>」または「<clinit>」の場合、NoSuchMethodException が発生します。それ以外の場合、反映されるメソッドは、次のアルゴリズムによって決定されます。このオブジェクトが表すクラスを C とします。

  • C で一致するメソッドが検索されます。一致するメソッドが見つからない場合、ステップ 1 のアルゴリズムが C のスーパークラスで再帰的に呼び出されます。

  • 上記のステップ 1 でメソッドが見つからなかった場合、一致するメソッドを求めて C のスーパーインターフェイスが検索されます。そのようなメソッドが見つかった場合、それが反映されます。

クラス C で一致するメソッドを検索するには: C が、指定された名前とまったく同じ仮パラメーター型を持つパブリック メソッドを 1 つだけ宣言する場合、それが反映されたメソッドです。そのようなメソッドが C に複数あり、これらのメソッドの 1 つが他のどのメソッドよりも具体的な戻り値の型を持っている場合、そのメソッドが反映されます。それ以外の場合は、いずれかの方法が任意に選択されます。

クラスに複数の一致するメソッドが存在する可能性があることに注意してください。これは、Java 言語ではクラスが同じシグネチャで異なる戻り値の型を持つ複数のメソッドを宣言することを禁止しているのに対し、Java 仮想マシンでは禁止されていないためです。この仮想マシンの柔軟性の向上は、さまざまな言語機能の実装に使用できます。たとえば、共変リターンはブリッジ メソッドで実装できます。ブリッジ メソッドとオーバーライドされるメソッドのシグネチャは同じですが、戻り値の型は異なります。

getMethodそのため、問題を解決する私のケースを呼び出す必要があります。

今、私はユーティリティクラスを持っています:

public class ReflectionUtils{

    private ReflectionUtils() {

    }

    public static <T> Method getMethod(Class<T> instanceClass, String name, Class<?>... parameterTypes) {   
        Method method = null;
        try {
            method = instanceClass.getDeclaredMethod(name,parameterTypes);
        }catch (Exception e) {
        }

        return method;
    }

    public static Object invokeOnMethod(Method method, Object obj, Object... args) {
        try {
            method.setAccessible(true);
            return method.invoke(obj,args);
        }catch (Exception e) {
            return null;
        }
    }
}

メソッドを変更してpublic static <T> Method getMethod(Class<T> instanceClass, String name, Class<?>... parameterTypes)、任意のアクセス修飾子のメソッドをトラップし、囲んでいるクラス、そのスーパークラス、またはインターフェイスのどこかに属するようにするには、どうすればよいですか?

4

2 に答える 2

0

わかった。これが私ReflectionUtils#getMethodが思いついたものです:

public static Method getMethod(Class<?> instanceClass, String name, Class<?>... parameterTypes) {
    if(ObjectUtils.notEqual(instanceClass,null) && StringUtils.isNotEmpty(name)) {
        Class<?> searchType = instanceClass;

        while (searchType != null) {
            Method[] methods = (searchType.isInterface() ? searchType.getMethods() : searchType.getDeclaredMethods());

            for (Method method : methods) {
                if (name.equals(method.getName()) && (parameterTypes == null || Arrays.equals(parameterTypes, method.getParameterTypes()))) {                           
                    return method;
                }
            }

            searchType = searchType.getSuperclass();
        }
    }       

    return null;
}

そして、それは機能します。イベントはスーパークラスのプライベートメソッドを返し、そのメソッドにアクセスできるようにした後、子オブジェクトをターゲットインスタンスとしてそのプライベートメソッドを呼び出すことができます.

コンソールに引数として渡されたメッセージを単純に出力するメソッドを作成しましたtest(String message)SortableDTO

それから私はしました:

SearchNeedsYearPlus2ArticleDTO dto = new SearchNeedsYearPlus2ArticleDTO();
Method test = ReflectionUtils.getMethod(dto.getClass(),"test",String.class);
System.out.println("Modifier of the method is private? : " + Modifier.isPrivate(test.getModifiers()));
ReflectionUtils.makeAccessible(test);
ReflectionUtils.invokeMethod(test,dto,"JYM");

そして出来上がり。できます。簡潔にするために、メソッドReflectionUtils#makeAccessibleとの定義はReflectionUtils#invokeMethod省略されていることに注意してください。:-)

出力は次のとおりです。

ここに画像の説明を入力

于 2013-07-20T10:09:16.347 に答える