Java反射学习(4)(“反射“机制获取成员方法及详细信息(Method类))
目录
一、基本引言。
(1)基本内容回顾。
(2)本篇博客的核心内容——基本介绍。
二、Java中使用"反射"机制获取成员方法及内部的详细信息。
(1)"反射"机制获取成员方法及详细信息的基本概念。
(2)利用Java的对象机制进行封装。(Method类)
1、构造方法。(Constructor类)
2、字段(成员变量)。(Field类)
3、成员方法。(Method类)
(3)操作成员方法的类"Method"相关的操作方法。
1、Class类中用于获取成员方法(返回Method类对象)的常用方法。
2、"Method"类中用于创建对象的方法。
3、"Method"类对象的重要且常用的操作方法。
(4)有关"Method"类的核心方法的操作演示。
<1>第一步。获取对应Student类的字节码文件对象(Class类)。
<2>第二步。通过Class对象获取Student类中对应成员方法"Method"对象。
<3>第三步。通过获取的成员方法"Method"对象获取其内部详细信息。
一、基本引言。
(1)基本内容回顾。
- 前面博客学习《Class类对象的三种实例化方式及使用时机、利用"反射"获取构造方法及详细信息——>Constructor类相关操作》Java反射学习(2)(“反射“机制获取构造方法及内部信息(Constructor类))-CSDN博客
- 上篇博客学习《利用"反射"获取成员变量及详细信息——>Field类的相关操作》
- Java反射学习(3)(“反射“机制获取成员变量及详细信息(Field类))-CSDN博客
(2)本篇博客的核心内容——基本介绍。
- 本篇博客的内容围绕:通过"反射"机制(.class字节码文件——>Class类对象)获取成员方法及详细信息——>Method类的相关操作。
- 原理图如下所示。
二、Java中使用"反射"机制获取成员方法及内部的详细信息。
(1)"反射"机制获取成员方法及详细信息的基本概念。
- 在Java中,反射是一种强大的机制,它允许程序在运行时访问、检查和修改它自己的结构,包括类、接口、字段和方法。
- 使用反射可以动态地调用方法、访问字段、构造对象等。
- 在介绍如何使用"反射"来获取类中(.class字节码文件)的成员变量及其详细信息的基本步骤之前需要先了解类"Method"。
(2)利用Java的对象机制进行封装。(Method类)
- 基于"Java万事万物皆对象"的机制。
- 使用.class(字节码文件)——(字节码文件对象)"Class"类对象获取对应类的信息。
1、构造方法。(Constructor类)
- 封装构造方法的实体类"Constructor"。(在引言中已经提及)
2、字段(成员变量)。(Field类)
- 封装成员变量的实体类"Field"。(在引言中已经提及)
3、成员方法。(Method类)
- 封装成员方法的实体类"Method"。(本篇博客讨论的重点)
(3)操作成员方法的类"Method"相关的操作方法。
1、Class类中用于获取成员方法(返回Method类对象)的常用方法。
- 简单识别法:带"s"的获取的值不只一个。带"declared"无视访问修饰符权限全部拿到。
- 注意:个别方法可以拿到父类的所有公共权限(public)的方法。
方法声明 功能描述 Method [] getMethods(); 返回所有公共成员方法对象的数组。
包括继承的。
Method [] getDeclaredMethods(); 返回所有成员方法(包括private)对象的数组。
不包括继承的。
Method getMethod
(String name, Class<?>...parameterTypes)
返回单个公共(public)成员方法对象。
parameterType:表示指定成员方法的参数类型——对应的类名.class(字节码文件对象)。
Method getDeclaredMethod(String name, Class<?>... parameterTypes) 返回单个成员方法(包括private)对象。
parameterType:表示指定成员方法的参数类型——对应的类名.class(字节码文件对象)。
2、"Method"类中用于创建对象的方法。
方法声明 功能描述 Object invoke(Object obj,Object...args);
(运行方法)
这个方法允许你在运行时调用任意一个已经通过反射获取到的Java方法
参数一:用obj对象调用该方法。
参数二:调用方法的传递的参数(如果没有就不写!)
返回值:方法的返回值(如果没有就不写!)
3、"Method"类对象的重要且常用的操作方法。
方法声明 功能描述 getModifiers(); 获取成员方法的权限修饰符。 getName(); 获取成员方法的名称。 getParameterTypes(); 获取成员方法的全部参数的类型。 getReturnType(); 获取成员方法的返回值类型。 getExceptionType(); 获取成员方法的抛出的全部异常类型。 newInstance(Object ...initargs) 通过反射调用类中的成员方法。 (4)有关"Method"类的核心方法的操作演示。
- 提供一个实体类:Student。
- Student类提供二个成员变量。
- 访问权限为private的成员变量name。
- 访问权限为private的成员变量age。
- 提供正常的构造方法(无参构造与有参构造方法)、getter与setter方法、toString()方法。
- 提供4个成员方法。其中两个成员方法是重载(参数个数不一致)。
- 访问权限为public的(无返回值)(无参)成员方法sleep()。里面打印控制台信息输出。
- 访问权限为private的(无返回值)成员方法eat(String food)。里面打印控制台信息输出。
- 访问权限为private的(无返回值)成员方法eat(String food,int num)。里面打印控制台信息输出。
- 访问权限为private的(有返回值)成员方法study(String context)。里面打印控制台信息输出。
- 最后会提供一个测试类(Main类)进行核心方法操作的测试。
<1>第一步。获取对应Student类的字节码文件对象(Class类)。
package com.fs.test; public class Main { public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException { //1.通过Student类的全限定类名获取class字节码文件对象 Class<?> clazz = Class.forName("com.fs.entity.Student"); } }
<2>第二步。通过Class对象获取Student类中对应成员方法"Method"对象。
- 通过字节码文件对象(Class对象)获取所有公共的(public)成员方法。
- getMethods()方法除了获取所有的公共成员方法外,还会获取到父类的公共成员方法。
package com.fs.test; import java.lang.reflect.Method; public class Main { public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException { //1.通过Student类的全限定类名获取class字节码文件对象 Class<?> clazz = Class.forName("com.fs.entity.Student"); //通过字节码文件对象(Class对象)获取所有公共的(public)成员方法 //还会获取到父类的成员方法 Method[] methods = clazz.getMethods(); for (Method method : methods) { System.out.println(method); } } }
通过字节码文件对象(Class对象)获取所有成员方法。(包括private修饰的成员方法)
getDeclaredMethods()方法:虽然可以获取子类的所有方法,但无法获取父类的方法。
package com.fs.test; import java.lang.reflect.Method; public class Main { public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException { //1.通过Student类的全限定类名获取class字节码文件对象 Class<?> clazz = Class.forName("com.fs.entity.Student"); //通过字节码文件对象(Class对象)获取所有的成员方法 //无法获取到父类的成员方法 Method[] methods = clazz.getDeclaredMethods(); for (Method method : methods) { System.out.println(method); } } }
- 通过字节码文件对象(Class对象)获取单个成员方法。
- String name, Class<?>...parameterTypes:方法名与参数类型(类名.class)。
- invoke()方法是Java反射API中的一个方法,它属于java.lang.reflect.Method类。这个方法允许你在运行时调用任意一个已经通过反射获取到的Java方法。
- 使用反射获取到的某个类的成员方法再调用——使用invoke()。若成员方法无返回值也可以不写(不接收)。
package com.fs.test; import com.fs.entity.Student; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; public class Main { public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException { //1.通过Student类的全限定类名获取class字节码文件对象 Class<?> clazz = Class.forName("com.fs.entity.Student"); //获取单个无参成员方法(public) Method sleep = clazz.getMethod("sleep"); Student s = new Student(); //使用反射调用方法 sleep.invoke(s); } }
- 通过字节码文件对象(Class对象)获取单个成员(可以获取private)方法。
package com.fs.test; import com.fs.entity.Student; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; public class Main { public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException { //1.通过Student类的全限定类名获取class字节码文件对象 Class<?> clazz = Class.forName("com.fs.entity.Student"); //获取单个有参成员方法(private) // 获取有参重载方法(eat)1个参数 Method eat1 = clazz.getDeclaredMethod("eat", String.class); //临时取消访问权限检查(因为是private权限的方法) eat1.setAccessible(true); eat1.invoke(new Student(), "苹果"); System.out.println("----------------------------------------------------------"); //获取有参重载方法(eat)2个参数 Method eat2 = clazz.getDeclaredMethod("eat", String.class, int.class); //临时取消访问权限检查(因为是private权限的方法) eat2.setAccessible(true); eat2.invoke(new Student(), "苹果", 10); } }
<3>第三步。通过获取的成员方法"Method"对象获取其内部详细信息。
- 通过字节码文件对象(Class对象)获取某个指定成员方法的访问权限修饰符。
package com.fs.test; import com.fs.entity.Student; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; public class Main { public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException { //1.通过Student类的全限定类名获取class字节码文件对象 Class<?> clazz = Class.forName("com.fs.entity.Student"); //获取单个无参成员方法(public) Method sleep = clazz.getMethod("sleep"); int modifiers = sleep.getModifiers(); System.out.println(modifiers); System.out.println("=================================================="); //获取单个有参成员方法(private) // 获取有参重载方法(eat)1个参数 Method eat1 = clazz.getDeclaredMethod("eat", String.class); int modifiers01 = eat1.getModifiers(); System.out.println(modifiers01); System.out.println("=================================================="); //获取有参重载方法(eat)2个参数 Method eat2 = clazz.getDeclaredMethod("eat", String.class, int.class); int modifiers02 = eat2.getModifiers(); System.out.println(modifiers02); } }
- 通过字节码文件对象(Class对象)获取某个指定成员方法的名称。
package com.fs.test; import com.fs.entity.Student; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; public class Main { public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException { //1.通过Student类的全限定类名获取class字节码文件对象 Class<?> clazz = Class.forName("com.fs.entity.Student"); //获取某个指定的成员方法对象 Method study = clazz.getDeclaredMethod("study", String.class); //获取成员方法的方法名 String methodName = study.getName(); System.out.println(methodName); } }
- 通过字节码文件对象(Class对象)获取某个指定成员方法的形参个数、形参类型或者获取到参数的数组对象!
package com.fs.test; import com.fs.entity.Student; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Parameter; public class Main { public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException { //1.通过Student类的全限定类名获取class字节码文件对象 Class<?> clazz = Class.forName("com.fs.entity.Student"); //获取某个指定的成员方法对象 Method eat = clazz.getDeclaredMethod("eat", String.class, int.class); //获取某个指定的成员方法对象参数个数 System.out.println("eat()方法的参数个数:"+eat.getParameterCount()); System.out.println("==========================================="); //获取某个指定的成员方法对象参数类型 Class<?>[] parameterTypes = eat.getParameterTypes(); for (Class<?> parameterType : parameterTypes) { System.out.println("参数类型:"+parameterType); } System.out.println("==========================================="); //直接获取某个指定的成员方法对象参数对象 Parameter[] parameters = eat.getParameters(); for (Parameter parameter : parameters) { System.out.println(parameter); } } }
- 通过字节码文件对象(Class对象)获取某个指定成员方法的抛出的所有异常!
package com.fs.test; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; public class Main { public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException { //1.通过Student类的全限定类名获取class字节码文件对象 Class<?> clazz = Class.forName("com.fs.entity.Student"); //获取某个指定的成员方法对象 Method study = clazz.getDeclaredMethod("study", String.class); Class<?>[] exceptionTypes = study.getExceptionTypes(); for (Class<?> exceptionType : exceptionTypes) { System.out.println("异常类型:"+exceptionType); } } }
- 通过字节码文件对象(Class对象)获取并允许某个指定成员方法。
- 使用方法:Object invoke(Object obj,Object...args);
- 参数1:表示调用该方法的对象。
- 参数2:指定成员方法的形参。(如果是空参,则可以不写)
- 方法的返回值:如果是void,则也可以不写(不必理会)。
- 调用方法如果访问权限修饰符是private,就要临时取消访问权限检查(方法setAccessaible())
package com.fs.test; import com.fs.entity.Student; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; public class Main { public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException { //1.通过Student类的全限定类名获取class字节码文件对象 Class<?> clazz = Class.forName("com.fs.entity.Student"); //获取某个指定的成员方法对象 Method studyMethod = clazz.getDeclaredMethod("study", String.class); //创建Student类对象。因为要使用该类对象才能调用该成员方法,所以需要创建对象 Student s = new Student(); //临时取消访问权限检验 studyMethod.setAccessible(true); //调用invoke()方法 //注意study()方法有返回值 String returnStr = (String) studyMethod.invoke(s, "java"); System.out.println(returnStr); } }