0x01 前言

学习了本章,那么如何获取类的名称与类的方法,就都可以大概了解,也可以为后面学习之路,扫除一些困难。

0x01.1 目录结构

  1. # 目录结构
  2. ├── 反射
  3. └── java动态加载类3
  4. ├── Test.java (用来做测试的方法)
  5. ├── Word.java

0x01.2 例子-Word类(用于理解的)

  1. // 该类具体路径: 反射.java获取类信息3.Word
  2. package 反射.java获取类信息3;
  3. public class Word {
  4. public void start() {
  5. System.out.println("start() 公共方法被成功访问");
  6. }
  7. public void end() {
  8. System.out.println("end() 公共方法被成功访问");
  9. }
  10. public String save(int id, String title, String content) {
  11. return "id: " + id + "; " + "title: " + title + "; " + "content: " + content;
  12. }
  13. public String add(String title, String content) {
  14. return "title: " + title + "; " + "content: " + content;
  15. }
  16. private String upload(String[] files) {
  17. return "upload() 私有方法被成功访问";
  18. }
  19. private String delUpload() {
  20. return "delUpload() 私有方法被成功访问";
  21. }
  22. }

0x02 获取当前类名称的方法

0x02.1 getName()

  1. getName() //得到类名称(包含路径)
  1. // 例如现在获取 int, String, double, Double, void 的类名称(包含路径)
  2. // 可以这样操作
  3. package 反射.java获取类信息3;
  4. public class Test {
  5. public static void main(String[] args) {
  6. Class c1 = int.class;
  7. Class c2 = String.class;
  8. Class c3 = double.class;
  9. Class c4 = Double.class;
  10. Class c5 = void.class;
  11. System.out.println(" ");
  12. System.out.println("============int.class===============");
  13. System.out.println(c1.getName());
  14. System.out.println("====================================");
  15. System.out.println(" ");
  16. System.out.println("============String.class===============");
  17. System.out.println(c2.getName());
  18. System.out.println("====================================");
  19. System.out.println(" ");
  20. System.out.println("============double.class===============");
  21. System.out.println(c3.getName());
  22. System.out.println("====================================");
  23. System.out.println(" ");
  24. System.out.println("============Double.class===============");
  25. System.out.println(c4.getName());
  26. System.out.println("====================================");
  27. System.out.println(" ");
  28. System.out.println("============void.class===============");
  29. System.out.println(c5.getName());
  30. System.out.println("====================================");
  31. System.out.println(" ");
  32. }
  33. }
  34. // 运行结果
  35. ============int.class===============
  36. int
  37. ====================================
  38. ============String.class===============
  39. java.lang.String
  40. ====================================
  41. ============double.class===============
  42. double
  43. ====================================
  44. ============Double.class===============
  45. java.lang.Double
  46. ====================================
  47. ============void.class===============
  48. void
  49. ====================================
  1. // 获取普通类的路径,也是一样的例如获取一下 0x01.2 例子-Word类 的类名称(包含路径)
  2. package 反射.java获取类信息3;
  3. public class Test {
  4. public static void main(String[] args) {
  5. Class w = Word.class;
  6. System.out.println(w.getName());
  7. }
  8. }
  9. // 运行结果
  10. 反射.java获取类信息3.Word

0x02.2 getSimpleName()

  1. getSimpleName() //得到类的简写名称(不包含包路径)
  1. // 例如现在获取 int, String, double, Double, void 的类名称(不包含包路径)
  2. // 可以这样操作
  3. package 反射.java获取类信息3;
  4. public class Test {
  5. public static void main(String[] args) {
  6. Class c1 = int.class;
  7. Class c2 = String.class;
  8. Class c3 = double.class;
  9. Class c4 = Double.class;
  10. Class c5 = void.class;
  11. System.out.println(" ");
  12. System.out.println("============int.class===============");
  13. System.out.println(c1.getSimpleName());
  14. System.out.println("====================================");
  15. System.out.println(" ");
  16. System.out.println("============String.class===============");
  17. System.out.println(c2.getSimpleName());
  18. System.out.println("====================================");
  19. System.out.println(" ");
  20. System.out.println("============double.class===============");
  21. System.out.println(c3.getSimpleName());
  22. System.out.println("====================================");
  23. System.out.println(" ");
  24. System.out.println("============Double.class===============");
  25. System.out.println(c4.getSimpleName());
  26. System.out.println("====================================");
  27. System.out.println(" ");
  28. System.out.println("============void.class===============");
  29. System.out.println(c5.getSimpleName());
  30. System.out.println("====================================");
  31. System.out.println(" ");
  32. }
  33. }
  34. // 运行结果
  35. ============int.class===============
  36. int
  37. ====================================
  38. ============String.class===============
  39. String
  40. ====================================
  41. ============double.class===============
  42. double
  43. ====================================
  44. ============Double.class===============
  45. Double
  46. ====================================
  47. ============void.class===============
  48. void
  49. ====================================
  1. // 获取普通类的路径,也是一样的例如获取一下 0x01.2 例子-Word类 的类名称(不包含包路径)
  2. package 反射.java获取类信息3;
  3. public class Test {
  4. public static void main(String[] args) {
  5. Class w = Word.class;
  6. System.out.println(w.getSimpleName());
  7. }
  8. }
  9. // 运行结果
  10. // 只返回类一个 Word.java 的类名称 Word
  11. Word

0x03 获取当前类所有的方法

0x03.1 getMethods()

  1. getMethods() // 获取的是所有的public的方法,包括父类继承而来的
  1. // 例如现在要获取 0x01.2 例子-Word类 所有public的方法,包括父类继承而来的
  2. package 反射.java获取类信息3;
  3. import java.lang.reflect.Method;
  4. public class Test {
  5. public static void main(String[] args) {
  6. try {
  7. // 获取Runtime类对象
  8. Class w = Class.forName("反射.java获取类信息3.Word");
  9. // 通过类类型,创建该类对象
  10. Object wObject = w.newInstance();
  11. // 获取类对象的运行时类的Class对象
  12. Class wc = wObject.getClass();
  13. /**
  14. * Method类, 方法对象
  15. * 一个成员方法就是一个Method类对象
  16. * getMethods()方法 获取的是所有的public的函数方法, 包括父类继承而来的
  17. */
  18. Method[] ms = wc.getMethods();
  19. for (int i = 0; i < ms.length; i++) {
  20. System.out.println(" ");
  21. System.out.println("====================================");
  22. System.out.println("方法名称是: " + ms[i].getName());
  23. // 获取参数类型-->得到的是参数列表的类型的类类型
  24. Class[] paramTypes = ms[i].getParameterTypes();
  25. for (int j = 0; j < paramTypes.length; j++) {
  26. System.out.println(
  27. " " +
  28. "参数" + (j+1) +
  29. "类型: " + paramTypes[j].getName() + ","
  30. );
  31. }
  32. System.out.println("方法的返回值的类类型: " + ms[i].getReturnType());
  33. }
  34. } catch (Exception e) {
  35. e.printStackTrace();
  36. }
  37. }
  38. }
  39. // 运行结果
  40. // 其中 add, start, save, end 是 Word类的公共方法
  41. // 其他的都是 Word类的默认父类方法
  42. ====================================
  43. 方法名称是: add
  44. 参数1类型: java.lang.String,
  45. 参数2类型: java.lang.String,
  46. 方法的返回值的类类型: class java.lang.String
  47. ====================================
  48. 方法名称是: start
  49. 方法的返回值的类类型: void
  50. ====================================
  51. 方法名称是: save
  52. 参数1类型: int,
  53. 参数2类型: java.lang.String,
  54. 参数3类型: java.lang.String,
  55. 方法的返回值的类类型: class java.lang.String
  56. ====================================
  57. 方法名称是: end
  58. 方法的返回值的类类型: void
  59. ====================================
  60. 方法名称是: wait
  61. 参数1类型: long,
  62. 参数2类型: int,
  63. 方法的返回值的类类型: void
  64. ====================================
  65. 方法名称是: wait
  66. 参数1类型: long,
  67. 方法的返回值的类类型: void
  68. ====================================
  69. 方法名称是: wait
  70. 方法的返回值的类类型: void
  71. ====================================
  72. 方法名称是: equals
  73. 参数1类型: java.lang.Object,
  74. 方法的返回值的类类型: boolean
  75. ====================================
  76. 方法名称是: toString
  77. 方法的返回值的类类型: class java.lang.String
  78. ====================================
  79. 方法名称是: hashCode
  80. 方法的返回值的类类型: int
  81. ====================================
  82. 方法名称是: getClass
  83. 方法的返回值的类类型: class java.lang.Class
  84. ====================================
  85. 方法名称是: notify
  86. 方法的返回值的类类型: void
  87. ====================================
  88. 方法名称是: notifyAll
  89. 方法的返回值的类类型: void

0x03.2 getDeclaredMethods()

  1. getDeclaredMethods() // 获取的是所有该类自己声明的方法,不问访问权限
  1. package 反射.java获取类信息3;
  2. import java.lang.reflect.Method;
  3. public class Test {
  4. public static void main(String[] args) {
  5. try {
  6. // 获取Runtime类对象
  7. Class w = Class.forName("反射.java获取类信息3.Word");
  8. // 通过类类型,创建该类对象
  9. Object wObject = w.newInstance();
  10. // 获取类对象的运行时类的Class对象
  11. Class wc = wObject.getClass();
  12. /**
  13. * Method类, 方法对象
  14. * 一个成员方法就是一个Method类对象
  15. * getDeclaredMethods()方法 获取的是所有该类自己声明的方法
  16. * 不问访问权限,父类继承来的就没有类,必须是该类自己声明的,才能获取
  17. */
  18. Method[] mds = wc.getDeclaredMethods();
  19. for (int i = 0; i < mds.length; i++) {
  20. System.out.println(" ");
  21. System.out.println("====================================");
  22. System.out.println("方法名称是: " + mds[i].getName());
  23. // 获取参数类型-->得到的是参数列表的类型的类类型
  24. Class[] paramTypes = mds[i].getParameterTypes();
  25. for (int j = 0; j < paramTypes.length; j++) {
  26. System.out.println(
  27. " " +
  28. "参数" + (j+1) +
  29. "类型: " + paramTypes[j].getName() + ","
  30. );
  31. }
  32. System.out.println("方法的返回值的类类型: " + mds[i].getReturnType());
  33. }
  34. } catch (Exception e) {
  35. e.printStackTrace();
  36. }
  37. }
  38. }
  39. // 运行结果
  40. // 获取的是 Word这个类所有的方法
  41. ====================================
  42. 方法名称是: add
  43. 参数1类型: java.lang.String,
  44. 参数2类型: java.lang.String,
  45. 方法的返回值的类类型: class java.lang.String
  46. ====================================
  47. 方法名称是: start
  48. 方法的返回值的类类型: void
  49. ====================================
  50. 方法名称是: save
  51. 参数1类型: int,
  52. 参数2类型: java.lang.String,
  53. 参数3类型: java.lang.String,
  54. 方法的返回值的类类型: class java.lang.String
  55. ====================================
  56. 方法名称是: upload
  57. 参数1类型: [Ljava.lang.String;,
  58. 方法的返回值的类类型: class java.lang.String
  59. ====================================
  60. 方法名称是: delUpload
  61. 方法的返回值的类类型: class java.lang.String
  62. ====================================
  63. 方法名称是: end
  64. 方法的返回值的类类型: void

0x04 调用某个类指定的成员方法

通过 getMethods() 与 getDeclaredMethods() 方法, 我们学习到了如何去获取类的名称和参数类型与返回类型。

那么如果我现在想要调用 某个类的指定方法 那就可以使用此方法。

0x04.1 getMethod()

  1. getMethod() // 获取的是当前类某个public的方法,包括父类继承而来的
  1. # 使用方法:
  2. # 方法1:
  3. Method method = clazz.getMethod("方法名");
  4. # 方法2:
  5. Method method = clazz.getMethod("方法名", 方法参数类型,多个参数用","号隔开);
  6. Method method = clazz.getMethod("方法名",String.class, int.class);

0x04.2 getDeclaredMethod()

  1. getDeclaredMethod() // 获取的是该类自己声明的某个方法,不问访问权限
  1. # 使用方法:
  2. # 方法1:
  3. Method method = clazz.getDeclaredMethod("方法名");
  4. # 方法2:
  5. Method method = clazz.getDeclaredMethod("方法名", 方法参数类型,多个参数用","号隔开);
  6. Method method = clazz.getDeclaredMethod("方法名",String.class, int.class);

0x04.3 invoke() - 通过反射调用方法

  1. # 反射调用方法
  2. 获取到java.lang.reflect.Method对象以后我们就可以通过Method对象的invoke方法来调用类方法
  3. # 调用类方法代码例子:
  4. method.invoke(方法实例对象, 方法参数值,多个参数用","号隔开);
  5. method.invoke(方法实例对象, "参数值1", "参数值2", "参数值3");

0x04.4 getMethod() 与 getDeclaredMethod() 使用例子

因为 getMethod() 与 getDeclaredMethod() 两个在实际调用中是一样的,
所以就不一个个区分啦

  1. # 例子1-调用无参数的公共start()方法
  2. # 使用的getMethod()
  3. package 反射.java获取类信息3;
  4. import java.lang.reflect.Method;
  5. public class Test {
  6. public static void main(String[] args) {
  7. try {
  8. Class w = Class.forName("反射.java获取类信息3.Word");
  9. // 通过类类型,创建该类对象
  10. Object wObject = w.newInstance();
  11. // 获取Word类 start方法
  12. Method a = w.getMethod("start");
  13. // 调用Word类 start方法
  14. Object aa = a.invoke(wObject);
  15. System.out.println(aa);
  16. } catch (Exception e) {
  17. e.printStackTrace();
  18. }
  19. }
  20. }
  21. # 运行结果
  22. start() 公共方法被成功访问
  23. null
  1. # 例子2-调用有参数的公共save()方法
  2. # 使用的getMethod()
  3. package 反射.java获取类信息3;
  4. import java.lang.reflect.Method;
  5. public class Test {
  6. public static void main(String[] args) {
  7. try {
  8. Class w = Class.forName("反射.java获取类信息3.Word");
  9. // 通过类类型,创建该类对象
  10. Object wObject = w.newInstance();
  11. // 获取Word类 save方法
  12. Method a = w.getMethod("save", int.class, String.class, String.class);
  13. // 调用Word类 save方法
  14. Object aa = a.invoke(wObject, 1, "标题1", "内容1");
  15. System.out.println(aa);
  16. } catch (Exception e) {
  17. e.printStackTrace();
  18. }
  19. }
  20. }
  21. // 运行结果
  22. id: 1; title: 标题1; content: 内容1
  1. # 例子3-调用有数组参数的私有upload()方法
  2. # 使用的getDeclaredMethod()
  3. # 注意: 在调用私有方法的时候
  4. # 必须要在使用 getDeclaredMethod() 的时候设置 setAccessible(true);
  5. # 不然无法调用私有方法
  6. package 反射.java获取类信息3;
  7. import java.lang.reflect.Method;
  8. public class Test {
  9. public static void main(String[] args) {
  10. try {
  11. Class w = Class.forName("反射.java获取类信息3.Word");
  12. // 通过类类型,创建该类对象
  13. Object wObject = w.newInstance();
  14. // 获取Word类 upload方法
  15. Method a = w.getDeclaredMethod("upload", String[].class);
  16. // 忽略访问修饰符的检查,这样就可以调用私有方法或是成员变量
  17. a.setAccessible(true);
  18. // 这里有个坑
  19. // 当我们的参数是数组的时候, 不能想当然的传个数组进去
  20. // 不然会提示:
  21. // java.lang.IllegalArgumentException: wrong number of arguments
  22. // 这是因为在java中 对方法传一个数组的时候, java会认为是多个参数
  23. // 解决方案: 把 fileArr 改为 new Object[]{fileArr} 传进去即可
  24. String[] fileArr = new String[]{"上传1", "上传2"};
  25. // 调用Word类 upload方法
  26. Object aa = a.invoke(wObject, new Object[]{fileArr});
  27. System.out.println(aa);
  28. } catch (Exception e) {
  29. e.printStackTrace();
  30. }
  31. }
  32. }
  33. // 运行结果
  34. upload() 私有方法被成功访问