访问封闭类或父类的方法的一般方法

时间:2013-07-20 07:32:25

标签: java class inheritance reflection methods

如何访问父类中定义的方法?这里我有以下继承:

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对象表示的类或接口。名字   parameter是一个String,它指定所需的简单名称   方法,而parameterTypes参数是Class对象的数组   以声明的顺序标识方法的形式参数类型。   如果在a中声明了多个具有相同参数类型的方法   class,其中一个方法的返回类型更多   特定于任何其他方法,返回该方法;除此以外   其中一种方法是任意选择的。如果名称是“&lt; init&gt;”或   “&LT; clinit&gt;” 中引发NoSuchMethodException。

Class#getMethod

  

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

     

如果名称是“&lt; init&gt;”或“&lt; clinit&gt;”引发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)以便它捕获任何访问修饰符的方法并且属于任何地方,封闭类或其超类或接口,我该怎么办?

2 个答案:

答案 0 :(得分:3)

根据继承主体,Dervied Classes不继承private方法。因此,在您的示例中,SearchNeedsYearPlus2ArticleDTO实例无法访问BaseSearchArticleDTO中声明的私有方法。

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

  • SearchNeedsYearPlus2ArticleDTOprivate, 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();
    }

答案 1 :(得分: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的定义。 : - )

这是输出:

enter image description here