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

返回一个 Method 对象,该对象反映此 Class 对象表示的类或接口的指定声明方法。name 参数是一个字符串,它指定所需方法的简单名称,parameterTypes 参数是一个 Class 对象数组,这些对象按照声明的顺序标识方法的形式参数类型。如果在一个类中声明了多个具有相同参数类型的方法,并且其中一个方法的返回类型比其他任何方法都更具体,则返回该方法;否则任意选择其中一种方法。如果名称是“<init>”或“<clinit>”,则会引发 NoSuchMethodException。

Class#getMethod

返回一个 Method 对象,该对象反映此 Class 对象表示的类或接口的指定公共成员方法。name 参数是一个字符串,指定所需方法的简单名称。parameterTypes 参数是一个 Class 对象数组,它们按照声明的顺序标识方法的形式参数类型。如果 parameterTypes 为 null,则将其视为空数组。

如果名称是“<init>”或“<clinit>”,则会引发 NoSuchMethodException。否则,要反映的方法由后面的算法决定。设 C 为该对象所代表的类:

  • 在 C 中搜索任何匹配的方法。如果没有找到匹配的方法,则在 C 的超类上递归调用步骤 1 的算法。

  • 如果在上面的步骤 1 中没有找到方法,则在 C 的超接口中搜索匹配方法。如果找到任何此类方法,则将其反映。

在 C 类中找到匹配的方法:如果 C 声明了一个具有指定名称和完全相同的形参类型的公共方法,则该方法被反映。如果在 C 中找到多个这样的方法,并且其中一个方法的返回类型比其他任何方法都更具体,则反映该方法;否则任意选择其中一种方法。

请注意,一个类中可能有多个匹配方法,因为虽然 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

3

根据继承原则,这些private方法不被派生类继承。因此,在您的示例SearchNeedsYearPlus2ArticleDTO实例中,无法访问在BaseSearchArticleDTO.

因此,使用 的Class对象SearchNeedsYearPlus2ArticleDTO,您可以访问

  • SearchNeedsYearPlus2ArticleDTO( private, protected, public)的所有方法
  • 层次结构中超类的所有继承方法 ( protected, public)

IMO你可以有一个这样的后备机制

try {
        Method m = instanceClass.getMethod(name); // try to get inherited method
        m.setAccessible(true); // if protected setAccessible
        m.invoke(instanceClass.newInstance());
    } catch(NoSuchMethodException ne) {
        try {
            Method m = instanceClass.getDeclaredMethod(name); // try to get declared method in the same class
            m.setAccessible(true); // if private setAccessible
            m.invoke(instanceClass.newInstance());
        } catch (Exception e) {
            e.printStackTrace();
        } 
    } catch (Exception e) {
        e.printStackTrace();
    }
于 2013-07-20T07:40:58.617 回答
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#makeAccessibleReflectionUtils#invokeMethod被省略。:-)

这是输出:

在此处输入图像描述

于 2013-07-20T10:09:16.347 回答