利用java反射调用类的的私有方法--转

时间:2023-12-17 15:27:08

原文:http://blog.csdn.net/woshinia/article/details/11766567

1,今天和一位朋友谈到父类私有方法的调用问题,本来以为利用反射很轻松就可以实现,因为在反射看来根本不区分是否是private的,没有想到调用本身的私有方法是可以的,但是调用父类的私有方法则不行,后来纠其原因很有可能是因为getDeclaredMethod方法和getMethod方法并不会查找父类的私有方法,于是只好自己写递归了,经过尝试果然如此。把代码放出来方便更多人。这段代码可以解决很多实际问题,不过利用反射来做的话性能不会太好。

  1. package com.syj.util.reflect;
  2. import java.lang.reflect.Method;
  3. /**
  4. * <p>
  5. * Title: 私有方法调用工具类
  6. * </p>
  7. *
  8. * <p>
  9. * Description:利用java反射调用类的的私有方法
  10. * </p>
  11. *
  12. * <p>
  13. * Copyright: Copyright (c) 2007
  14. * </p>
  15. *
  16. * @author 孙钰佳
  17. * @main sunyujia@yahoo.cn
  18. * @date Jun 1, 2008 10:18:58 PM
  19. */
  20. public class PrivateUtil {
  21. /**
  22. * 利用递归找一个类的指定方法,如果找不到,去父亲里面找直到最上层Object对象为止。
  23. *
  24. * @param clazz
  25. *            目标类
  26. * @param methodName
  27. *            方法名
  28. * @param classes
  29. *            方法参数类型数组
  30. * @return 方法对象
  31. * @throws Exception
  32. */
  33. public static Method getMethod(Class clazz, String methodName,
  34. final Class[] classes) throws Exception {
  35. Method method = null;
  36. try {
  37. method = clazz.getDeclaredMethod(methodName, classes);
  38. } catch (NoSuchMethodException e) {
  39. try {
  40. method = clazz.getMethod(methodName, classes);
  41. } catch (NoSuchMethodException ex) {
  42. if (clazz.getSuperclass() == null) {
  43. return method;
  44. } else {
  45. method = getMethod(clazz.getSuperclass(), methodName,
  46. classes);
  47. }
  48. }
  49. }
  50. return method;
  51. }
  52. /**
  53. *
  54. * @param obj
  55. *            调整方法的对象
  56. * @param methodName
  57. *            方法名
  58. * @param classes
  59. *            参数类型数组
  60. * @param objects
  61. *            参数数组
  62. * @return 方法的返回值
  63. */
  64. public static Object invoke(final Object obj, final String methodName,
  65. final Class[] classes, final Object[] objects) {
  66. try {
  67. Method method = getMethod(obj.getClass(), methodName, classes);
  68. method.setAccessible(true);// 调用private方法的关键一句话
  69. return method.invoke(obj, objects);
  70. } catch (Exception e) {
  71. throw new RuntimeException(e);
  72. }
  73. }
  74. public static Object invoke(final Object obj, final String methodName,
  75. final Class[] classes) {
  76. return invoke(obj, methodName, classes, new Object[] {});
  77. }
  78. public static Object invoke(final Object obj, final String methodName) {
  79. return invoke(obj, methodName, new Class[] {}, new Object[] {});
  80. }
  81. /**
  82. * 测试反射调用
  83. *
  84. * @param args
  85. */
  86. public static void main(String[] args) {
  87. PrivateUtil.invoke(new B(), "printlnA", new Class[] { String.class },
  88. new Object[] { "test" });
  89. PrivateUtil.invoke(new B(), "printlnB");
  90. }
  91. }
  92. class A {
  93. private void printlnA(String s) {
  94. System.out.println(s);
  95. }
  96. }
  97. class B extends A {
  98. private void printlnB() {
  99. System.out.println("b");
  100. }
  101. }

程序的输出结果为
test
b
说明private方法调用成功了不管是自己的私有方法还是父类的私有方法。\

2,

  1. package me.test;
  2. import java.lang.reflect.*;  //导入反射需要的包
  3. public class ReflectTest {
  4. public static void main(String[] args)  throws  Exception
  5. {
  6. /*  下面通过反射完成对一个对象中成员的替换
  7. *   并且执行执行私有方法
  8. *   完成对 Poiont类的对象中所有的 String的对象的d换成x
  9. *   并且类中无修改方法
  10. */
  11. Point pt=new Point(3,5);  //创建一个Point对象
  12. Field fx=pt.getClass().getField("x") ;  //获取x的映射类对象
  13. Field fy=pt.getClass().getDeclaredField("y");//因为y是私有的所以要调用这个方法
  14. Method m2=Point.class.getDeclaredMethod("showPrivate") ;//获得私有方法映射类
  15. //利用反射调用共有输出
  16. m2.setAccessible(true)  ;// 修改showPrivate 权限 改变为可以调用
  17. m2.invoke(pt) ;//执行私有方法
  18. //利用成员反射输出x 和 私有的 y
  19. System.out.println(fx.getInt(pt));//反射输出x
  20. fy.setAccessible(true) ;//改变私有为可访问
  21. System.out.println(fy.getInt(pt));//输出私有y
  22. //替换成员后并且反射私有方法输出
  23. changeString(pt) ;//反射替换成员值
  24. System.out.println(pt);
  25. }
  26. public static void changeString(Object obj)  throws Exception//反射替换对所有String进行替换
  27. {
  28. Field[] f=obj.getClass().getFields()  ; //获得成员映射数组
  29. for(Field tem : f)  //迭代for循环
  30. {
  31. if(tem.getType()==String.class)  //内存中只有一份String字节码
  32. {
  33. String oldString=(String)tem.get(obj) ;  //返回内容
  34. String newString=oldString.replace('d', 'x');//将所有b替换为x
  35. tem.setAccessible(true);
  36. tem.set(obj, newString) ;//替换成员值
  37. }
  38. }
  39. }
  40. }
  41. public class Point
  42. {
  43. public int x  ;
  44. private int y  ;
  45. public Point(int x, int y) {
  46. super();
  47. this.x = x;
  48. this.y = y;
  49. }
  50. public String  a="dsfdsfd"  ;  //只有 共有可以替换
  51. public String  b="fdsfdsfewewwwww"  ;
  52. public String  c="adddssss"  ;
  53. private void showPrivate()  //私有方法输出
  54. {
  55. System.out.println("x="+this.x+"\n"+"y="+this.y);
  56. System.out.println(this.a);
  57. System.out.println(this.b);
  58. System.out.println(this.c);
  59. }
  60. public String toString()
  61. {
  62. return this.a+"\n"+this.b+"\n"+this.c;
  63. }
  64. }

3,

Java利用反射来获取一个方法的 范型化参数 Vector<Integer>的类型

  1. class   A
  2. {
  3. public  void   show(Vector<Integer> v)  {}
  4. }
  5. 在我们不知道Vector中数据的类型的时候 这时候我们只知道这个方法的名字  和参数的个数 ,我们来获取 范型化的实际类型 。
  6. 我们不可能通过 Vector对应的Class类来反射出  泛型集合中的类型  ,但是 我们却可以通过 这个方法所对应的Method类来实现 。
  7. 具体如下  :
  8. import java.lang.reflect.Method;
  9. import java.lang.reflect.ParameterizedType;
  10. import java.lang.reflect.Type;
  11. import java.util.Vector;
  12. public class Test3
  13. {
  14. public static void main(String []args) throws SecurityException, NoSuchMethodException
  15. {
  16. Method  m=A.class.getMethod("show", Vector.class) ;      //反射获得show方法的Method对象
  17. Type[]t=m.getGenericParameterTypes() ;      //获得范型参数的 一个Type数组  Type是Class类的基类 GenericArrayType, ParameterizedType, TypeVariable<D>, WildcardType  这些都是 实现Type的子接口
  18. ParameterizedType p=(ParameterizedType)t[0];     //强制转换成Type的子接口 ParameterizedType类型 因为这个接口又可以获得 范型化集合中元素的类型    System.out.println(p.getRawType());                     //获得集合的类型
  19. System.out.println(p.getActualTypeArguments()[0]);   //获得集合中元素的类型
  20. }
  21. }