2013-07-20 47 views
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对象表示的 的类或接口指定已声明方法的方法的对象。名称 参数是一个字符串,它指定所需 方法的简单名称,parameterTypes参数是一个Class对象数组 ,它们按声明顺序标识方法的形式参数类型。 如果在 类中声明了多个具有相同参数类型的方法,并且其中一个方法的返回类型比其他任何方法更具有 特定性,则会返回该方法;否则 的方法之一是任意选择。如果名称是“<init>”或 “<clinit>”,则引发NoSuchMethodException。

Class#getMethod

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

如果名称是 “<INIT> ”或“ <clinit>” 一个NoSuchMethodException提高。否则,要反映的方法由以下算法 确定。令C为此对象代表的类别:

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

  • 如果在上面的步骤1中找不到方法,则搜索C的超接口以寻找匹配方法。如果发现任何此类 方法,则会反映出来。

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

请注意,类中可能存在多个匹配方法,因为尽管Java语言禁止类声明具有相同签名但不同返回类型的多个方法,但Java虚拟机不会。虚拟机中增加的灵活性 可用于实现各种语言功能。例如, covariant返回可以用桥接方法实现;桥接方法和 方法被覆盖将具有相同的签名但不同的返回类型。

所以我需要拨打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),使其捕获任何访问修饰符的方法,属于任何地方,在外围类,或者它的父类或界面,我该怎么做?

回答

3

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

所以,用的SearchNeedsYearPlus2ArticleDTO一个Class对象,你可以访问层级(protected, public

  • 所有的SearchNeedsYearPlus2ArticleDTOprivate, 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(); 
        } 
    
+0

+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; 
} 

它的工作原理。事件返回超类的私有方法,并使该方法可访问后,您可以调用该子对象作为目标实例的私有方法。

我在SortableDTO中创建了一个方法test(String message),它只是打印在控制台中作为参数传递的消息。

然后我做:

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