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));