反射
**定义:**就是在程序运行的过程中,通过类对象(字节码对象)可以获取到所有的静态属性,调用所有的静态方法。
还可以通过 类对象(字节码对象) 创建实例对象,访问实例对象的所有实例属性,调用实例对象的所有方法。
作用:
- 可以通过字符串传参的形式操作一个类
- 可以在原有代码的功能基础上做扩充 (拿到了字节码.class文件,但是没有获取到源代码的情况。)
类对象的加载和初始化:
类加载器 classLoader:
BootClassLoader 加载核心的jdk的 jre/lib/rt.jar包
ExtClassLoader 加载 jre/lib/ext 里的包
AppClassLoader 加载自己写的 类
自定义类加载器
使用类加载器的目的:是为了加载一个 .class 文件,把它加载成为一个 Class 类型的 类对象(字节码对象)
然后再通过 Class 类型的 类对象操作 属性和方法以及创建实例对象
哪些情况下会初始化一个类:
类的初始化过程:
1.静态成员变量设置默认值。
2.初始化父类对象。
3.给静态成员变量赋值以及执行静态代码块。
类什么时候被加载:
1.创建对象之前,类会被加载。
a.使用关键字new创建这个类的实例对象之前,这个类会被加载。
b.使用反射通过字节码对象创建实例对象之前,这个类也会被加载。
2.访问静态方法以及静态成员变量时,这个类也会被初始化;需要注意的是,如果访问的是静态成员常量,这个类不会被加载。
3.当这个类有main方法,执行main方法的时候这个类也会被初始化。
4.当子类需要初始化时,父类也会初始化。
5.当A类被B类引用的时候,B类加载时,也会加载A类。
类只会被加载一次,初始化也只初始化一次,对象可以初始化多次。
类不会被初始化的场景:
1.如果使用了这个类里的静态常量,这个类不会被初始化
2.如7果使用了 子类.父类的静态变量名 方式访问父类的静态变量,只会初始化父类,不会初始化子类。
3.用某各类型声明数组并创建数组对象时,不会导致这个类初始化。
Person[] people = new Person[4]; Person 类 不会被初始化。
加载的顺序: 双亲委托机制 根加载器 --> 扩展记载其 --> 应用加载器
Class.forName(“java.lang.Integer”);
不会使用应用加载器加载到 out 文件夹下 java.lang.Integer 类
而是使用 BootClassLoader 加载到了 jdk 里的 Integer 类
最基本最核心的就是获取一个类的类对象
获取类对象的方式:
- 类名.class 2. 实例对象名.getClass 3. Class.forName(完整的包名) 4. classLoader.loadClass(完整包名);
使用类对象创建一个实例对象,调用类对象的 newInstance 方法可以创建一个实例对象
newInstance 调用的是 默认(空参数)的构造方法,如果没有空参构造方法,会报错!
获取到一个类对象以后,可以访问所有属性,调用所有的方法。
Constructor类: 字节码对象里的构造方法
Method类: 字节码对象里的普通方法
Field类: 字节码对象里的属性