java反射机制详细解析

java反射机制详细解析

基本概念

通常情况下编写代码都是固定的,无论运行多少次执行的结果也是固定的,在某些特殊场合中编写代码时不确定要创建什么类型的对象,也不确定要调用什么样的方法,这些都希望通过运行时传递的参数来决定,该机制叫做动态编程技术,也就是反射机制

通俗来说,反射机制就是用于动态创建对象并且动态调用方法的机制

目前主流的框架底层都是采用反射机制实现的。

如:

Person p = new Person(); - 表示声明Person类型的引用指向Person类型的对象

p.show(); - 表示调用Person类中的成员方法show

Class类

基本概念

java.lang.Class类的实例可以用于描述Java应用程序中的接口,也就是一种数据类型

该类没有公共构造方法,该类的实例由Java虚拟机和类加载器自动构造完成,本质上就是加载到内存中的运行时类

获取Class对象的方式

  1. 使用数据类型.class的方式可以获取对应类型的Class对象(掌握)。

     // 1.使用数据类型.class的方式可以获取对应的Class对象
            // 1.1 获取字符串类型来获取Class对象并打印
            Class aClass = String.class;
            System.out.println(aClass); // 自动调用 toString 方法 打印结果是 class 或者 interface  完全限定名(包名.类名)
            // 1.2 获取基本数据类型的class对象并打印
            aClass = int.class;
            System.out.println(aClass); // int
            // 1.3 获取 void 类型的class对象并打印结果
            aClass = void.class;
            System.out.println(aClass); // void
    
  2. 使用引用/对象.getClass()的方式可以获取对应类型的Class对象。

    // 2.使用 对象.getClass() 方法来获取Class队形
            // 2.1 使用 对象.getClass() 方法获取字符串类型的Class对象并打印
            String str = new String();
            aClass = str.getClass();
            System.out.println(aClass); // class java.lang.Integer
            // 2.2 使用 对象.getClass() 获取保障类的Class对象并打印
            Integer integer = Integer.valueOf(5);
            aClass = integer.getClass();
            System.out.println(aClass); // class java.lang.Integer
            // 2.3使用基本数据类型调用该方法并打印
            int num = 10;
            // num.getClass(); 编译报错 没有该方法 所以基本数据类型不能调用该方法
    
  3. 使用包装类.TYPE的方式可以获取对应基本数据类型的Class对象

            // 3.使用包装类中的type()方法获取Class对象
            // 3.1获取Integer类型的Class对象
            aClass = Integer.TYPE;
            System.out.println(aClass); // int
            // 3.2获取Character类型的Class对象
            aClass = Character.TYPE;
            System.out.println(aClass); // char
            // 3.3获取Boolean类型的Class对象
            aClass = Boolean.TYPE;
            System.out.println(aClass); // boolean
    
  4. 使用Class.forName()的方式来获取参数指定类型的Class对象(掌握)。

    	    // 4.使用Class类的中方法forName的方式来获取参数指定类型的Class对象
            // 4.1 获取String类型的Class对象并打印
            // aClass = Class.forName("String"); ClassNotFoundException
            aClass = Class.forName("java.lang.String");
            System.out.println(aClass); // class java.lang.String
            // 4.2传入基本数据类型 获取Class对象 
            // aClass = Class.forName("int"); // ClassNotFoundException 因为基本数据类型不是对象
    
  5. 使用类加载器ClassLoader的方式获取指定类型的Class对象。

    	   // 5.使用类加载器ClassLoader获取Class类型的对象
            ClassLoader classLoader = ClassTest.class.getClassLoader();
            aClass = classLoader.loadClass("java.lang.String");
            System.out.println(aClass); // class java.lang.String
    
  6. 注意事项

    1. 包装类使用type方法获取的是对应的基本数据类型 而 使用 包装类的对象.getClass() 方法获取的对应包装类的对象
    2. 通过 .class类获取的对象 调用toString的方法时 打印结果有三种
      1. 如果对象是引用数据类型 返回值是 class 完全限定名称
      2. 如果对象是基本数据类型 返回值是 基本数据类型
      3. 如果对象为 void 则返回值为 void
    3. 基本数据类型不能通过getClass的方法获取Class对象 因为基本数据类型不是对象
    4. 通过Class.forname() 方式获取Class对象 要求参数是完全限定名 否则会报ClassNotFountException 类找不到异常
    5. 通过Class.forName() 方式获取Class对象 不能获取基本数据类型的Class对象

常用的方法(掌握)

方法声明 功能介绍
static Class<?> forName(String className) 用于获取参数指定类型对应的Class对象并返回
T newInstance() 用于创建该Class对象所表示类的新实例(已过时 使用Constructor 中的 newInstance()方法)

方法演示

  1. 动态创建指定类型的对象

    	   // 1.使用原始方式以无参的形式构造 Person 类型的对象 并打印
            Person person = new Person();
            System.out.println(person); // null 0
            // 2.使用反射机制以无参形式构造 person 类型的对象 并打印
            // 2.1 指定类型的动态创建对象
            Class c1 = Class.forName("cn.junnsunny.modal4.day05.Person");
            System.out.println(c1.newInstance()); // null 0
    
  2. 从键盘输入创建类型的对象

    	   // 2.2 创建用户从键盘输入的对象
            Scanner sc = new Scanner(System.in);
            String str = sc.next(); // cn.junnsunny.modal4.day05.Person
            // Class c1 = Class.forName("cn.junnsunny.modal4.day05.Person");
            Class c1 = Class.forName(str);
            System.out.println(c1.newInstance()); // Person{name='null', age=0}
    	    sc.close();
    
  3. 读取配置文件动态创建配置文件的对象

    		// 2.3 创建从配置文件a.txt中的对象
            // 文件中存放的字符是 cn.junnsunny.modal4.day05.Person
            // 2.3.1创建BufferedReader 类型的输入流对象 并与 z:/a.txt 关联
            BufferedReader reader = new BufferedReader(new FileReader("z:/a.txt"));
            // 2.3.2读取配置文件a.txt中一行数据
            String str = reader.readLine();
            // 2.3.3使用Class.forName() 创建该全限定名的Class对象
            Class c1 = Class.forName(str);
            // 2.3.4使用newInstance() 创建该class类型的实例化对象并打印
    	   // newInstance方法中的实参适用于给有参构造方法的形参进行初始化的 也就是给name和age进行初始化的
            System.out.println(c1.newInstance()); // Person{name='null', age=0}
        }
    

Constructor类(构造方法)

基本概念

java.lang.reflect.Constructor类主要用于描述获取到的构造方法信息

Class类的常用方法

方法声明 功能介绍
Constructor getConstructor(Class… parameterTypes) 用于获取此Class对象所表示类型中参数指定的 公共构造方法
Constructor[] getConstructors() 用于获取此Class对象所表示类型中所有的公共 构造方法

Constructor类的常用方法

方法声明 功能介绍
T newInstance(Object…initargs) 使用此Constructor对象描述的构造方法来构造Class对象代表类型的新实例
int getModifiers() 获取方法的访问修饰符
String getName() 获取方法的名称
Class<?>[]getParameterTypes() 获取方法所有参数的类型

Constructor类的常用方法的使用

  1. 使用 Constructor 创建无参构造Person类

    	   // 1.读取配置文件 获取创建Person类型的全限定类名 文件在 z:/a.txt
            BufferedReader reader = new BufferedReader(new FileReader("z:/a.txt"));
            // 2.读取配置文件中的内容并返回
            String s = reader.readLine();
            // 3.通过获取的全限定类名使用Class.forName的方法获取Class对象
            Class c = Class.forName(s);
            // 4.通过Class类型的对象使用getConstructor获取对应的无参Person类型的无参构造
            Constructor constructor = c.getConstructor();
            // 5.通过Constructor的对象创建Person的无参构造 并打印
            System.out.println(constructor.newInstance()); // Person{name='null', age=0}
    
  2. 使用 Constructor 创建有参构造Person类

    	   // 2.使用原始的方式以有参的方式构造Person类型的对象并打印
            Person person1 = new Person("张三", 20);
            System.out.println(person1); // Person{name='张三', age=20}
            // 3.使用反射机制以有参的方式获取Person类型的对象
            // 3.1读取配置文件 获取创建Person类型的全限定类名 文件在 z:/a.txt
            BufferedReader reader = new BufferedReader(new FileReader("z:/a.txt"));
            // 3.2读取配置文件中的内容并返回
            String s = reader.readLine();
            // 3.3通过获取的全限定类名使用Class.forName的方法获取Class对象
            Class c = Class.forName(s);
            // 3.4通过Class类型的对象使用getConstructor获取对应的无参Person类型的无参构造
            // 相当于获取Class对象对应类中的有参构造方法 也就是Person类中的有参构造
            Constructor constructor = c.getConstructor(String.class, int.class);
            // 3.5通过Constructor的对象创建Person的有参构造 并打印
            System.out.println(constructor.newInstance("张三",20)); // Person{name='张三', age=20}
    
  3. 使用 Constructor 获取Person类所有的构造方法并打印

     		// 4.使用反射机制获取Person类中所有的公共构造方法并打印
            // 4.1读取配置文件 获取创建Person类型的全限定类名 文件在 z:/a.txt
            BufferedReader reader = new BufferedReader(new FileReader("z:/a.txt"));
            // 4.2读取配置文件中的内容并返回
            String s = reader.readLine();
            // 4.3通过获取的全限定类名使用Class.forName的方法获取Class对象
            Class c = Class.forName(s);
            // 4.4通过Class类型的对象使用getConstructor获取对应的无参Person类型的全部的构造方法
            Constructor[] constructors = c.getConstructors();
            // 4.5遍历数组集合 使用f增强for的方式
            for (Constructor ct: constructors){
          
          
                // 4.6 打印权限修饰符
                System.out.println("构造方法的权限修饰符是: " + ct.getModifiers()); // 1 java中的常量值 代表public修饰
                // 4.7 打印方法名
                // 打印结果是 cn.junnsunny.modal4.day05.Person 全限定类名
                System.out.println("构造方法的方法名称是: " + ct.getName()); 
                // 4.8 打印参数列表
                // 打印结果是 无参构造为 空 有参构造是  class java.lang.String int
                System.out.print("构造方法的所有参数类型是: "); 
                Class[] parameterTypes = ct.getParameterTypes();
                for (Class sc : parameterTypes){
          
          
                    System.out.print(sc + " ");
                }
                System.out.println();
            }
    

Field类(成员变量)

基本概念

java.lang.reflect.Field类主要用于描述获取到的单个成员变量信息

Class类的常用方法

方法声明 功能介绍
Field getDeclaredField(String name) 用于获取此Class对象所表示类中参数指定的单个成员变量信息
Field[] getDeclaredFields() 用于获取此Class对象所表示类中所有成员变量信息

Field类的常用方法

方法声明 功能介绍
Object get(Object obj) 获取参数对象obj中此Field对象所表示成员变量的数值
void set(Object obj, Object value) 将参数对象obj中此Field对象表示成员变量的数值修改为参数 value的数值
void setAccessible(boolean flag) 当实参传递true时,则反射对象在使用时应该取消 Java 语言访 问检查
int getModifiers() 获取成员变量的访问修饰符
Class<?> getType() 获取成员变量的数据类型
String getName() 获取成员变量的名称

Field类的常用方法的使用

  1. 使用反射机制并获取成员变量的返回值信息并打印

    public static void main(String[] args) throws Exception {
          
          
            // 1.使用原始的方式构造对象以及获取成员变量的数值并打印
            Person person = new Person("张三", 20);
            System.out.println(person.name); // 张三
    
            // 2.使用反射机制构造方法并获取成员变量的返回值信息
            // 2.1 获取对应的Class对象
            Class c = Class.forName("cn.junnsunny.modal4.day05.Person");
            // 2.2通过Class对象来获取有参构造方法
            Constructor constructor = c.getConstructor(String.class, int.class);
            // 2.3使用有参构造方法来创建对应的实例
            Object obj = constructor.newInstance("张三", 20);
            // 2.4使用class对象获取成员变量信息
            // 获取成员的字段信息只能用public修饰 否则会报 IllegalAccessException 非法访问异常
            // 解决方法: 设置取消语言访问检查 暴力反射
            field.setAccessible(true);
            Field field = c.getDeclaredField("name"); 
            // 2.5打印Person类中的对象获取到的成员信息
            System.out.println(field.get(obj)); // 张三
        }
    
  2. 使用反射机制修改成员变量的值信息并打印修改之后的数据

            // 2.使用原始的方式修改指定成员变量的数值并再次打印
            Person person = new Person("张三", 20);
            person.name = "李四";
            System.out.println(person.name); // 李四
            // 3.使用反射机制修改指定的成员变量信息并打印修改后的信息
            // 3.1获取对应的Class的对象
            Class c = Class.forName("cn.junnsunny.modal4.day05.Person");
            // 3.2通过Class对象获取对应的有参构造方法
            Constructor constructor = c.getConstructor(String.class, int.class);
            // 3.3通过构造方法创建对应的对象
            Object obj = constructor.newInstance("张三", 20);
            // 3.4通过Class获取对应的对应的成员变量
            Field field = c.getDeclaredField("name");
            //  获取成员的字段信息只能用public修饰 否则会报 IllegalAccessException 非法访问异常
            // 解决方法: 设置取消语言访问检查
            field.setAccessible(true);
            // 3.5通过对象修改成员变量的信息
            field.set(obj,"李四");
            // 3.6打印对象中成员变量修改的数值
            System.out.println(field.get(obj)); // 李四
    
  3. 使用反射机制所有的获取成员信息并打印

            // 3.使用反射机制所有的获取成员信息并打印
            // 3.1获取对应的Class的对象
            Class c = Class.forName("cn.junnsunny.modal4.day05.Person");
            // 3.2通过Class对象获取对应的有参构造方法
            Constructor constructor = c.getConstructor(String.class, int.class);
            // 3.3通过构造方法创建对应的对象
            Object obj = constructor.newInstance("张三", 20);
            // 3.4通过Class对应获取所有的成员信息
            Field[] declaredFields = c.getDeclaredFields();
            // 3.5变量数组并打印数组中的信息
            for (Field declaredField : declaredFields) {
          
          
                System.out.println("成员变量的权限修饰是:" + declaredField.getModifiers()); // 2 2 
                System.out.println("成员变量的数据类型是:" + declaredField.getType()); // class java.lang.String int
                System.out.println("成员变量的名称是:" + declaredField.getName()); // name age
            }
    

Method类(成员方法)

基本概念

java.lang.reflect.Method类主要用于描述获取到的单个成员方法信息。

Class类的常用方法

方法声明 功能介绍
Method getMethod(String name, Class<?>… parameterTypes) 用于获取该Class对象表示类中名字为name参数为parameterTypes的指定公共成员方法
Method[] getMethods() 用于获取该Class对象表示类中所有公共成员方法

Method类的常用方法

方法声明 功能介绍
Object invoke(Object obj, Object… args) 使用对象obj来调用此Method对象所表示的成员方法,实 参传递args
int getModifiers() 获取方法的访问修饰符
Class<?> getReturnType() 获取方法的返回值类型
String getName() 获取方法的名称
Class<?>[] getParameterTypes() 获取方法所有参数的类型
Class<?>[] getExceptionTypes() 获取方法的异常信息

Method类的常用方法的使用

  1. 使用反射机制构造对象 调用成员方法并打印结果

            // 1.使用原始方式构造对象并打印结果
            Person person = new Person("张三", 20);
            System.out.println("调用方法的返回值是: " + person.getName());  // 张三
    
            // 2.使用反射机制构造对象并打印结果
            // 2.1获取对应的Class对象
            Class c = Class.forName("cn.junnsunny.modal4.day05.Person");
            // 2.2通过Class对象获取有参的构造方法
            Constructor constructor = c.getConstructor(String.class, int.class);
            // 2.3通过有参的方式实例化对象
            Object obj = constructor.newInstance("张三", 20);
            // 2.4通过Class对象获取对象的方法
            // 2.4.1获取设置姓名的方法(有参方法)
            Method setName = c.getMethod("setName",String.class);
            // 2.4.2获取修改姓名的方法(无参方法)
            Method getName = c.getMethod("getName");
            // 2.5通过Method对象调用该方法并打印返回值
            System.out.println("调用方法的返回值是: " + getName.invoke(obj)); // 张三
            setName.invoke(obj,"李四");
            System.out.println("调用方法的返回值是: " + getName.invoke(obj)); // 李四
    
  2. 使用反射机制获取Class对象中的所有公共方法并打印

    	    // 2.使用反射机制获取Class对象中的所有公共方法并打印
            // 2.1获取对应的Class对象
            Class c = Class.forName("cn.junnsunny.modal4.day05.Person");
            // 2.2通过Class对象获取有参的构造方法
            Constructor constructor = c.getConstructor(String.class, int.class);
            // 2.3通过有参的方式实例化对象
            Object obj = constructor.newInstance("张三", 20);
            // 2.4通过Class对象获取对象的所有方法
            Method[] methods = c.getMethods();
            // 2.5变量Method集合并打印 方法的返回值类型 方法名 权限修饰符 形式参数
            for (Method method : methods) {
          
          
                System.out.println("成员方法的权限修饰符是: " + method.getModifiers());
                System.out.println("成员方法的方法名称是: " + method.getName());
                System.out.println("成员方法的返回值类型是: " + method.getReturnType());
                System.out.print("成员方法的形式参数是: ");
                Class<?>[] parameterTypes = method.getParameterTypes();
                for (Class<?> parameterType : parameterTypes) {
          
          
                    System.out.print(parameterType + ", ");
                }
                System.out.println();
                System.out.println("获取的异常信息是: ");
                Class<?>[] exceptionTypes = method.getExceptionTypes();
                for (Class<?> exceptionType : exceptionTypes) {
          
          
                    System.out.print(exceptionType+ ", ");
                }
                System.out.println();
            }
    

获取其它结构信息(class类)

方法声明 功能介绍
Package getPackage() 获取所在的包信息
Class<? super T> getSuperclass() 获取继承的父类信息
Class<?>[] getInterfaces() 获取实现的所有接口
Annotation[] getAnnotations() 获取注解信息
Type[] getGenericInterfaces() 获取泛型信息

猜你喜欢

转载自blog.csdn.net/Junsunnyl/article/details/119973352