Java——反射

一、类的加载  

  当程序要使用某个类时,如果该类还未被加载到内存中,则系统会通过加载,连接,初始化三步来实现对这个类进行初始化

  加载

    就是将class文件读入内存,并为之创建一个Class对象

    任何类被使用时系统都会建立一个Class对象

  连接

    验证 是否有正确的内部结构,并和其他类协调一致

    准备 负责为类的静态成员分配内存,并设置默认初始化值

    解析 将类的二进制数据中的符号引用替换为直接引用

 ** 初始化**

二、类初始化时机

  创建类的实例

  访问类的静态变量 ,或者为静态变量赋值

  调用类的静态方法

  使用反射方式来强制创建某个类或接口对应的java.lang.Class对象

  初始化某个类的子类

  直接使用java.exe命运来运行某个主类

三、类加载器

  负责将.class文件加载到内存中,并为之生成对应的Class对象。

  虽然我们不需要关心类加载机制,但是了解这个机制我们就能更好的理解程序的运行。

  类加载器的组成

    Bootstrap ClassLoader 根类加载器

    Extension ClassLoader 扩展类加载器

    System ClassLoader 系统类加载器

四、反射

  java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;

  对于任意一个对象,都能够任意调用它的任意一个方法和属性;

  这种动态获取的信息以及动态调对象的方法的功能称为java语言的反射机制。

  想要解剖一个类,必须先要获取到该类的字节码文件对象。

  而解剖使用的就是Class类中的方法。

  所以先要获取到每一个字节码文件对应的Class类型的对象

五、通过反射获取构造方法

  类中的成员:

    成员变量:Field

    构造方法:Constructor

    成员方法:Method

 
获取类的Class对象
  //方式1:在对象已经存在的前提下获取
  Student student = new Student("xiaohei",18,"anhui","nan");
  Class<? extends Student> studentClass = student.getClass();
  

  //方式2:通过类名.class的方式获取 在同步锁的场景下用的比较多
  Class<Student> studentClass2 = Student.class;
  System.out.println(studentClass2==studentClass);
 

  //方式3:最常用的方式 利用Class类中的静态方法
  //static Class<?> forName(String className) 传入的是类的路径
  Class<?> studentClass = Class.forName("com.shujia.day17.Student");

Constructor<T> getConstructor(Class<?>... parameterTypes) 只能某一个获取公共的构造方法-
返回一个 Constructor对象,该对象反映 Constructor对象表示的类的指定的公共 类函数。

Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes) 获取某一个任意权限修饰符的构造方法

Constructor<?>\[\] getDeclaredConstructors() 获取所有的任意权限修饰符的构造方法

使用获取到的公共的构造方法
Constructor<?> constructor = studentClass.getConstructor(String.class, int.class, String.class, String.class);
T newInstance(Object... initargs)
Object o = constructor.newInstance("xxx", 18, "xxx", "男");
System.out.println(o);

使用获取到的私有的构造方法创建对象
Constructor<?> declaredConstructor = studentClass.getDeclaredConstructor();
绕过权限校验,暴力访问
declaredConstructor.setAccessible(true);
Object o = declaredConstructor.newInstance();
System.out.println(o);

六、通过反射获取成员变量并赋值

获取类的字节码文件对象

Class<?> studentClass = Class.forName("com.shujia.day17.Student");
Field getField(String name) 只能通过变量名获取公共的成员变量----------------------------------------------
Field gender = studentClass.getField("gender");
System.out.println(gender);
Field\[\] getFields() 只能获取所有公共的成员变量 ---------------------------------------------
Field\[\] fields = studentClass.getFields();
System.out.println(Arrays.toString(fields));

Field getDeclaredField(String name) 通过变量名获取任意权限修饰符的成员变量 ------------------------
Field name = studentClass.getDeclaredField("name");
System.out.println(name);
Field\[\] getDeclaredFields() 获取所有成员变量 ---------------------------------------------
Field\[\] declaredFields = studentClass.getDeclaredFields();
System.out.println(Arrays.toString(declaredFields));

七、通过反射获取成员方法并赋值

获取类的字节码文件对象
Class<?> studentClass = Class.forName("com.shujia.day17.Student");
Method getMethod(String name, Class<?>... parameterTypes) 只能获取公共的成员方法,当前和父类的公共都可以----------------------
Method fun4 = studentClass.getMethod("fun4");
System.out.println(fun4);
Method fun5 = studentClass.getMethod("fun5", String.class);
System.out.println(fun5);
Method fun1 = studentClass.getMethod("wait");
System.out.println(fun1);
getMethods 获取当前类及其父类中的所有公共的成员方法------------------------------------------
Method\[\] methods = studentClass.getMethods();
System.out.println(Arrays.toString(methods));

getDeclaredMethod() 获取任意一个权限修饰符的成员方法----------------------------------------
Method fun1 = studentClass.getDeclaredMethod("fun1");
System.out.println(fun1);

getDeclaredMethods 获取当前类中的所有成员方法----------------------------------------
Method\[\] declaredMethods = studentClass.getDeclaredMethods();
System.out.println(Arrays.toString(declaredMethods));