反射的定义

将类的各个组成部分封装成对象,这就是反射机制;或者说是在运行过程中动态获取类,调用方法。
下图是关于类加载的过程

38c607671366966c8e0b6f8aa0b0c4e.jpg

类从编写到创建对象运行分为三个阶段

1)源代码编译阶段 通过编译器将.java文件编译成.class文件;
2)类对象阶段 通过类加载器将 .class文件加载到内存 然后通过反射将类的成员变为对象的形式;
3)运行阶段 new 了一个对象在堆中分配了地址,这个过程叫作类的运行时阶段。

反射的好处

在类的运行时可以动态的知道对象的信息。只需要拿到类的Class对象

获取Class对象的三种方式

1、Class.forName(“全类名”) 全类名=包名+类名 应用场景多用于配置文件 传入一个字符串路径
2、类名.class 多用于参数传递 比如锁 传入要锁的对象;
3、对象,getClass() 当知道对象是啥可以 通过对象的getClass()对象的getClass()方法获取类对象。

通过反射获取类的父类和其所有实现的接口

1、第一步获取类对象信息;
2、调用getInterfaces()方法获取。
代码如下

  1. public class TestReflectDemo2 implements Serializable,Runnable {
  2. public static void main(String[] args) throws ClassNotFoundException {
  3. Class<?> class3 = null;
  4. class3 = Class.forName("reflect.TestReflectDemo2");
  5. //第二步 通过 类对象的 getSuperclass(); 获取该类的父类
  6. Class<?>[] interfaces = class3.getInterfaces();
  7. for (Class<?> anInterface : interfaces) {
  8. System.out.println(anInterface.getName());
  9. }
  10. }
  11. @Override
  12. public void run() {
  13. }
  14. }

通过反射获取类所有的构造获取属性类似

1、先拿到类的Class类对象信息;
2、通过调用getConstructors()方法获取类所有的构造
代码如下

  1. public class TestReflectDemo3 {
  2. public static void main(String[] args) throws Exception{
  3. //通过反射实例化Student对象
  4. Class<?> class1 = Class.forName("reflect.Student");
  5. Student student =(Student)class1.newInstance();
  6. student.setName("张三");
  7. System.out.println(student);
  8. //通过反射获取所有的构造
  9. Constructor<?>[] constructors = class1.getConstructors();
  10. for (Constructor<?> constructor : constructors) {
  11. for (int i = 0; i < constructor.getParameterTypes().length; i++) {
  12. if(i==constructor.getParameterTypes().length-1){
  13. //获取构造的参数类型
  14. System.out.println(constructor.getParameterTypes()[i].getName());
  15. }else {
  16. System.out.print(constructor.getParameterTypes()[i].getName()+",");
  17. }
  18. }
  19. }
  20. //调用构造返回一个对象
  21. Student student1 = (Student) constructors[0].newInstance("李松",13);
  22. System.out.println(student1);
  23. }
  24. }

通过反射获取类所有的方法并执行方法
1、获取类的Class对象;
2、通过class对象调用getMethod()方法返回一个Method对象数组,通过该数组拿到方法信息;
3、方法名.invoke()方法调用方法 需要传入调用的对象 。

  1. package reflect;
  2. import java.lang.reflect.Method;
  3. import java.lang.reflect.Modifier;
  4. public class TestReflectDemo5 {
  5. public static void main(String[] args)throws Exception {
  6. Class<?> class1 = Class.forName("reflect.TestReflectDemo5");
  7. //获取类的所有方法
  8. Method[] methods = class1.getMethods();
  9. for (int i = 0; i < methods.length; i++) {
  10. //获取方法权限修饰符
  11. int temp = methods[i].getModifiers();
  12. Class<?>[] para = methods[i].getParameterTypes();
  13. //获取方法返回值
  14. Class<?> returnType = methods[i].getReturnType();
  15. // System.out.println("方法名: "+methods[i].getName()+" "+"返回值类型: "+returnType.getName()+" "+ Modifier.toString(temp) + " ");
  16. for (int j = 0; j < para.length; ++j) {
  17. System.out.print(para[j].getName() + " " + "arg" + j);
  18. if (j < para.length - 1) {
  19. System.out.print(",");
  20. }
  21. }
  22. }
  23. }
  24. }
  1. package reflect;
  2. import java.lang.reflect.Method;
  3. /**
  4. * 通过反射机制调用某个类的方法
  5. */
  6. public class TestReflectDemo6 {
  7. public static void main(String[] args) throws Exception{
  8. Class<?> class1 = Class.forName("reflect.TestReflectDemo6");
  9. //通过反射机制调用方法
  10. //得到一个Method对象 调用没有参数的方法
  11. Method fun1 = class1.getMethod("fun1");
  12. //调用方法 传入调用者
  13. fun1.invoke(class1.newInstance());
  14. //调用有参数的方法 一定得指明传入参数的class信息
  15. Method fun2 = class1.getMethod("fun2",String.class,int.class);
  16. fun2.invoke(class1.newInstance(),"张三",12);
  17. }
  18. public void fun1(){
  19. System.out.println("通过反射机制调用该方法");
  20. }
  21. //定义有参数的方法
  22. public void fun2(String name ,int age){
  23. System.out.println(name+age);
  24. }
  25. }