image.png
#https://blog.csdn.net/a745233700/article/details/82893076(参考)

一、 基本概念

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

通俗来说,反射机制就是用于动态创建对象并且动态调用方法的机制。
目前主流的框架底层都是采用反射机制实现的。

如:
Person p = new Person(); - 表示声明Person类型的引用指向Person类型的对象
p.show(); - 表示调用Person类中的成员方法show

二、 Class类

(1) 基本概念

  • java.lang.Class类的实例可以用于描述Java应用程序中的类和接口,也就是一种数据类型。
  • 该类没有公共构造方法,该类的实例由Java虚拟机和类加载器自动构造完成,本质上就是加载到内
  • 存中的运行时类。

    (2) 获取Class对象的方式

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

  • 使用引用/对象.getClass()的方式可以获取对应类型的Class对象。
  • 使用包装类.TYPE的方式可以获取对应基本数据类型的Class对象。
  • 使用Class.forName()的方式来获取参数指定类型的Class对象(掌握)。
  • 使用类加载器ClassLoader的方式获取指定类型的Class对象。

    (3) 常用的方法(掌握)

    image.png
    image.png
    (4)创建对象的两种方式
    原始创建~
    反射创建~
    注意:newInstance的方法已经过时了,所以在通过Constuctor去实例化对象(在“三”中有讲解) ```java package task20;

import java.io.*; import java.util.Scanner; import java.util.UUID;

public class ClassTest { public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, IOException { //1,使用原始方式实例化对象 Person p1=new Person(); System.out.println(“无参创建的方式是:”+p1); //0 null //2,使用反射的方式实例化对象,此时是直接给定了一个类类型 Class<?> c1=Class.forName(“task20.Person”); c1.newInstance(); System.out.println(“反射方式实例化对象:”+c1.newInstance());

  1. //也可以通过键盘输入
  2. Scanner sc=new Scanner(System.in);
  3. String str1=sc.next();
  4. Class<?> c2=Class.forName(str1);
  5. System.out.println("从键盘输入的对象实例化:"+c2);
  6. //由此我们也可以知道,还能从配置文件中读取输入
  7. BufferedReader br=new BufferedReader(new InputStreamReader(new FileInputStream("d:/a.txt")));
  8. String str=br.readLine();
  9. Class<?> c3=Class.forName(str);
  10. System.out.println("从配置文件中读取的对象实例化"+c3.newInstance());
  11. br.close();
  12. }

}

  1. <a name="j7chh"></a>
  2. # ![image.png](https://cdn.nlark.com/yuque/0/2021/png/22605889/1633103015026-f2b74de6-ad2e-47eb-aa0f-e29be7cc9427.png#clientId=u7af1f6bd-c886-4&from=paste&height=187&id=u4073c1e4&margin=%5Bobject%20Object%5D&name=image.png&originHeight=249&originWidth=1400&originalType=binary&ratio=1&size=280213&status=done&style=none&taskId=u4ac0c3b6-ab15-448a-81fa-02286bce28a&width=1050)
  3. <a name="UxyVD"></a>
  4. # 三、Constructor类
  5. <a name="lRG3b"></a>
  6. ## (1)基本概念
  7. - java.lang.reflflect.Constructor类主要用于描述获取到的构造方法信息
  8. <a name="ioJsu"></a>
  9. ## (2)Class类的常用方法
  10. ![image.png](https://cdn.nlark.com/yuque/0/2021/png/22605889/1633097974065-6f40b513-9d1d-4906-9eb0-ff5ea8269276.png#clientId=ub6b268e3-f938-4&from=paste&height=188&id=u34591132&margin=%5Bobject%20Object%5D&name=image.png&originHeight=251&originWidth=1025&originalType=binary&ratio=1&size=61101&status=done&style=none&taskId=u4beb7edf-fc48-4438-b1ca-c525c47b556&width=769)
  11. <a name="VPEtD"></a>
  12. ## (3)使用Constructor无参构造实例化对象
  13. ```java
  14. package task20;
  15. import java.io.*;
  16. import java.lang.reflect.Constructor;
  17. import java.util.Scanner;
  18. import java.util.UUID;
  19. public class ClassTest {
  20. public static void main(String[] args) throws Exception {
  21. //1,使用原始方式实例化对象
  22. Person p1=new Person();
  23. System.out.println("无参创建的方式是:"+p1); //0 null
  24. //2,使用反射的方式实例化对象,此时是直接给定了一个类类型
  25. Class<?> c1=Class.forName("task20.Person");
  26. //c1.newInstance();
  27. //System.out.println("反射方式实例化对象:"+c1.newInstance());
  28. Constructor<?> constructor = c1.getConstructor();
  29. System.out.println("无参方式创建的对象:"+constructor.newInstance());
  30. /* //也可以通过键盘输入
  31. Scanner sc=new Scanner(System.in);
  32. String str1=sc.next();
  33. Class<?> c2=Class.forName(str1);
  34. System.out.println("从键盘输入的对象实例化:"+c2);
  35. //由此我们也可以知道,还能从配置文件中读取输入
  36. BufferedReader br=new BufferedReader(new InputStreamReader(new FileInputStream("d:/a.txt")));
  37. String str=br.readLine();
  38. Class<?> c3=Class.forName(str);
  39. System.out.println("从配置文件中读取的对象实例化"+c3.newInstance());*/
  40. }
  41. }

(4)使用有参构造方法实例化对象

image.png
image.png
(5)Constructor类的常用方法
image.png
(5)获取类中的所有构造方法的参数信息

  1. Constructor<?>[] constructors = c1.getConstructors();
  2. for (Constructor ct:constructors
  3. ) {
  4. System.out.println("构造方法的访问修饰符是:"+ct.getModifiers());
  5. System.out.println("构造方法的名称为:"+ct.getName());
  6. System.out.println("参数类型是:");
  7. Class[] parameterTypes = ct.getParameterTypes();
  8. for (Class ps:parameterTypes
  9. ) {
  10. System.out.println(ps);
  11. }
  12. }

image.png
1表示public

四、Field类

(1)基本概念

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

(2) Class类的常用方法

image.png

(3)Field类的常用方法

image.png

(4)获取成员变量数值的两种方式

  1. package task20;
  2. import java.lang.reflect.Constructor;
  3. import java.lang.reflect.Field;
  4. public class PersonFieldTest {
  5. public static void main(String[] args) throws Exception {
  6. //1使用原始的方式获取类的成员变量的信息
  7. Person p1=new Person(10,"林三");
  8. System.out.println(p1.getName());
  9. //1-2如果name为public修饰的,可以直接p1.name访问
  10. System.out.println("---------------------------");
  11. //2 使用反射机制制造对象,并获取成员变量的数据并打印
  12. //2.1 获取Class对象
  13. Class<?> aClass = Class.forName("task20.Person");
  14. //2.2 根据Clss对象获取(有参)Constructor构造方法
  15. Constructor<?> constructor = aClass.getConstructor(int.class, String.class);
  16. //2.3 使用有参构造方法得到Person类型的对象
  17. Object object = constructor.newInstance(10, "王五");
  18. //2.4 根据Class对象获取对应的成员变量信息 name为成员字段的名字
  19. Field name1 = aClass.getDeclaredField("name");
  20. //2.5 使用person类型的对象获取成员变量的数值并打印 获取对应字段的值
  21. System.out.println("获取到的成员变量信息为:"+name1.get(object));
  22. }
  23. }

(5)修改成员变量数值的两种方式

  1. package task20;
  2. import java.lang.reflect.Constructor;
  3. import java.lang.reflect.Field;
  4. public class PersonFieldTest {
  5. public static void main(String[] args) throws Exception {
  6. //1使用原始的方式获取类的成员变量的信息
  7. Person p1=new Person(10,"林三");
  8. System.out.println(p1.getName());
  9. //1-2如果name为public修饰的,可以直接p1.name访问
  10. System.out.println("---------------------------");
  11. //2 使用反射机制制造对象,并获取成员变量的数据并打印
  12. //2.1 获取Class对象
  13. Class<?> aClass = Class.forName("task20.Person");
  14. //2.2 根据Clss对象获取(有参)Constructor构造方法
  15. Constructor<?> constructor = aClass.getConstructor(int.class, String.class);
  16. //2.3 使用有参构造方法得到Person类型的对象
  17. Object object = constructor.newInstance(10, "王五");
  18. //2.4 根据Class对象获取对应的成员变量信息 name为成员字段的名字
  19. Field field = aClass.getDeclaredField("name");
  20. //设置java语言访问检查
  21. //field.setAccessible(true);
  22. //2.5 使用person类型的对象获取成员变量的数值并打印 获取对应字段的值
  23. System.out.println("获取到的成员变量信息为:"+field.get(object));
  24. System.out.println("--------------------------------");
  25. //3,修改成员变量的值
  26. //使用原始方式去进行修改
  27. // p1.name="张三";
  28. //System.out.println("通过原始方式修改后的值为"+p1.name);
  29. //4,使用反射机制修改指定对象成员变量中的值
  30. //修改object对象中的成员变量名为field的数值为关羽,即修改Person中name的值为关羽
  31. field.set(object,"关羽");
  32. System.out.println("通过反射修改的值为"+field.get(object));
  33. }
  34. }

如果访问的成员变量的修饰符为public,则直接访问和通过反射访问都没问题

如果访问的成员变量的修饰符为private,则不能直接访问,通过反射机制进行访问时,要进行java语言访问检查设置,这个也称为暴力反射。
image.png

  1. package task20;
  2. import java.lang.reflect.Constructor;
  3. import java.lang.reflect.Field;
  4. public class PersonFieldTest {
  5. public static void main(String[] args) throws Exception {
  6. //1使用原始的方式获取类的成员变量的信息
  7. Person p1=new Person(10,"林三");
  8. System.out.println(p1.getName());
  9. //1-2如果name为public修饰的,可以直接p1.name访问
  10. System.out.println("---------------------------");
  11. //2 使用反射机制制造对象,并获取成员变量的数据并打印
  12. //2.1 获取Class对象
  13. Class<?> aClass = Class.forName("task20.Person");
  14. //2.2 根据Clss对象获取(有参)Constructor构造方法
  15. Constructor<?> constructor = aClass.getConstructor(int.class, String.class);
  16. //2.3 使用有参构造方法得到Person类型的对象
  17. Object object = constructor.newInstance(10, "王五");
  18. //2.4 根据Class对象获取对应的成员变量信息 name为成员字段的名字
  19. Field field = aClass.getDeclaredField("name");
  20. //设置java语言访问检查
  21. field.setAccessible(true); /*** 设置!!!***/
  22. //2.5 使用person类型的对象获取成员变量的数值并打印 获取对应字段的值
  23. System.out.println("获取到的成员变量信息为:"+field.get(object));
  24. System.out.println("--------------------------------");
  25. //3,修改成员变量的值
  26. //使用原始方式去进行修改
  27. // p1.name="张三";
  28. //System.out.println("通过原始方式修改后的值为"+p1.name);
  29. //4,使用反射机制修改指定对象成员变量中的值
  30. //修改object对象中的成员变量名为field的数值为关羽,即修改Person中name的值为关羽
  31. field.set(object,"关羽");
  32. System.out.println("通过反射修改的值为"+field.get(object));
  33. }
  34. }

(6)获取所有成员变量的实现

  1. //5,获取所有成员变量
  2. Field[] declaredFields = aClass.getDeclaredFields();
  3. for (Field ds:declaredFields
  4. ) {
  5. System.out.println("获取到的成员变量的修饰符为"+ds.getModifiers());
  6. System.out.println("获取到的成员变量的类型为"+ds.getType());
  7. System.out.println("获取到的成员变量名称为"+ds.getName());
  8. System.out.println("---------------------------------------");
  9. }

五、Method类

(1)基本概念

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

(2)Class类的常用方法

image.png

(3)Method类的常用方法

image.png

(4)获取成员方法的方式

  1. //6,使用反射机制制造对象,并调用方法打印结果
  2. // 6.1 使用Class类制造对象
  3. Class<?> aClass1 = Class.forName("task20.Person");
  4. // 6.2 使用Constructor方法获取有参构造方法
  5. Constructor<?> constructor1 = aClass1.getConstructor(int.class, String.class);
  6. // 6.3 使用有参的构造方法制造对象
  7. Object object2 = constructor1.newInstance(20, "好家伙");
  8. // 6.4 根据Class对象获取对象的成员方法
  9. Method method=aClass1.getMethod("getName");
  10. // 6.5 使用对象调用成员方法并打印 相当于调用object2的getName()方法
  11. System.out.println("调用方法的返回是:"+method.invoke(object2));

(5)获取所有成员方法的实现

  1. package com.lagou.task20;
  2. import java.lang.reflect.Constructor;
  3. import java.lang.reflect.Method;
  4. public class PersonMethodTest {
  5. public static void main(String[] args) throws Exception {
  6. // 1.使用原始方式构造对象并调用方法打印结果
  7. Person p1 = new Person("zhangfei", 30);
  8. System.out.println("调用方法的返回值是:" + p1.getName()); // zhangfei
  9. System.out.println("------------------------------------------------------");
  10. // 2.使用反射机制构造对象并调用方法打印结果
  11. // 2.1 获取Class对象
  12. Class c1 = Class.forName("com.lagou.task20.Person");
  13. // 2.2 根据Class对象来获取对应的有参构造方法
  14. Constructor constructor = c1.getConstructor(String.class, int.class);
  15. // 2.3 使用有参构造方法构造对象并记录
  16. Object object = constructor.newInstance("zhangfei", 30);
  17. // 2.4 根据Class对象来获取对应的成员方法
  18. Method method = c1.getMethod("getName");
  19. // 2.5 使用对象调用成员方法进行打印
  20. // 表示使用object对象调用method表示的方法,也就是调用getName方法来获取姓名
  21. System.out.println("调用方法的返回值是:" + method.invoke(object)); // zhangfei
  22. System.out.println("------------------------------------------------------");
  23. // 3.使用反射机制来获取类中的所有成员方法并打印
  24. Method[] methods = c1.getMethods();
  25. for (Method mt : methods) {
  26. System.out.println("成员方法的修饰符是:" + mt.getModifiers());
  27. System.out.println("成员方法的返回值类型是:" + mt.getReturnType());
  28. System.out.println("成员方法的名称是:" + mt.getName());
  29. System.out.println("成员方法形参列表的类型是:");
  30. Class<?>[] parameterTypes = mt.getParameterTypes();
  31. for (Class ct : parameterTypes) {
  32. System.out.print(ct + " ");
  33. }
  34. System.out.println();
  35. System.out.println("成员方法的异常类型列表是:");
  36. Class<?>[] exceptionTypes = mt.getExceptionTypes();
  37. for (Class ct: exceptionTypes) {
  38. System.out.print(ct + " ");
  39. }
  40. System.out.println();
  41. System.out.println("---------------------------------------------------");
  42. }
  43. }
  44. }

六、获取其它结构信息

image.png

  1. package com.lagou.task20;
  2. import java.io.Serializable;
  3. @MyAnnotation
  4. public class Student<T, E> extends Person implements Comparable, Serializable {
  5. @Override
  6. public int compareTo(Object o) {
  7. return 0;
  8. }
  9. }
  1. package com.lagou.task20;
  2. import java.lang.annotation.Annotation;
  3. import java.lang.reflect.Type;
  4. public class StudentTest {
  5. public static void main(String[] args) throws Exception {
  6. // 获取Student类型的Class对象
  7. Class c1 = Class.forName("com.lagou.task20.Student");
  8. System.out.println("获取到的包信息是:" + c1.getPackage());
  9. System.out.println("获取到的父类信息是:" + c1.getSuperclass());
  10. System.out.println("-------------------------------------------------");
  11. System.out.println("获取到的接口信息是:");
  12. Class[] interfaces = c1.getInterfaces();
  13. for (Class ct : interfaces) {
  14. System.out.print(ct + " ");
  15. }
  16. System.out.println();
  17. System.out.println("-------------------------------------------------");
  18. System.out.println("获取到的注解信息是:");
  19. Annotation[] annotations = c1.getAnnotations();
  20. for (Annotation at : annotations) {
  21. System.out.print(at + " ");
  22. }
  23. System.out.println();
  24. System.out.println("-------------------------------------------------");
  25. System.out.println("获取到的泛型信息是:");
  26. Type[] genericInterfaces = c1.getGenericInterfaces();
  27. for (Type tt : genericInterfaces) {
  28. System.out.print(tt + " ");
  29. }
  30. System.out.println();
  31. }
  32. }

image.png