18.1 类的加载 连接 初始化
类的加载:加载 连接 初始化
所有的类,都是一个java.lang.Class对象
加载 读取.class文件,在内存中生成对应的Class文件
连接
初始化 静态变量和静态代码块的初始化
JVM最先初始化的总是java.lang.Obeject对象
类初始化的时机:
6种
特例:
1、对于一个final型的静态类变量,如果该Field的值在编译时就可以确定下来,那么这个Field相当于宏变量,编译时直接替换,程序使用该静态Field也不会导致该类的初始化
2、使用ClassLoader类的loadClass方法来加载某个类时,只是加载该类,并不会执行该类的初始化,使用Class的forName静态方法才会导致强制初始化该类
18.2 类加载器
JVM中同一个类只会被加载一此,那么如何区分不同的类呢?
全限定类名+类加载器名
当JVM启动时,会形成由3个类加载器组成的初始类加载器层次结构:
Bootstrap ClassLoader根类加载器,负责加载Java的核心类;不是Java.lang.ClassLoader的子类,不是用Java实现的 rt.jar
Extension ClassLoader 扩展类加载器,负责加载JRE的扩展目录(%JAVA_HOME%/jre/lib/ext或者java.ext.dirs)中JAR包的类; /lib/ext
System ClassLoader 系统类加载器,负责在JVM启动时加载来自java命令-classpath选项、java.class.path系统属性,或CLASSPATH环境变量所指定的JAR包和类路径
类加载机制:全盘负责、父类委托、缓存机制
4种类型加载器的层次
用户类加载器—》系统类加载器—》扩展类加载器—》根类加载器
JVM中除根类加载器外的所有类加载器,都是ClassLoader的子类
Class的缓存,如果已经加载了,缓存中存在,就不会再次加载
18.3 通过反射查看类信息
对象的编译时类型和运行时类型
java.lang.Class 诸多方法
获得Class对象:
1、使用Class类的forName(String clazzName)静态方法;clazzName不需要提前确定
2、调用某个类的class属性(Person.class);这种方式更安全,性能更好
3、调用某个对象的getClass()方法,该方法继承自Object
Class<?> getClass() 返回此 Object 的运行时类。
从Class中获取信息:
Class对象可以获取类中的方法Method、构造器Constructor、成员变量Field
Field 成员变量
要确定一个方法,需要由方法名和形参列表来确定,但是形参名没有任何意义,所以只能由形参类型来确定
18.4 通过反射生成并操作对象
Class对象可以获取类中的方法Method、构造器Constructor、成员变量Field
通过反射来创建对象:
1、使用Class对象的newInstance()方法来创建该Class对象对应的实例,
这种方式要求该Class对象的对应类有默认构造器
2、使用Class对象获取指定的Constructor对象,再调用Constructor对象的newInstance()方法来创建该Class对象对应类的实例
方法可以指定某一特定构造函数来生成对象
通过反射来调用方法:
mtd.invoke(target , config.getProperty(name));
通过Method的invoke方法来调用对应的方法时,Java会要求程序必须有调用该方法的权限。
当确实需要调用某个对象的private方法,可以先调用setAccessible(boolean flag)取消访问权限检查。Method、Constructor和Field都可以调用该方法
采用这种办法,即可通过反射访问到类的私有成员
Spring架构:配置文件配置对象,由程序根据配置文件来创建对象
通过反射来访问成员变量:
通过反射来操作数组:
通过Array开动态生成数组