Java基础第四篇-类加载机制与反射
类加载机制与反射
1.类的加载、连接和初始化
JVM和类
一个Java程序启动一个Java虚拟机进程,当系统被终结时,JVM进程也会被终止。
有以下几种情况:
程序运行到最后正常结束
程序使用System.exit()结束程序
程序遇到未捕获的异常或者错误而结束
程序平台强制结束了JVM进程
类的加载
首先将类的class文件读入内存,创建一个java.lang.class对象。
类的连接
当类被加载之后,系统会生成一个对应的Class对象,接着把类的二进制数据合并到JRE中
类的初始化
虚拟机对类进行初始化,主要是静态Field进行初始化
2.类加载器
类加载器负责将.class文件加载到内存中,并生成java.lang.class对象。
类加载机制
全盘负责:当一个雷加载器负责加载某个Class时,该Class所依赖的和引用的其他Class也将由此类加载器负责载入
父类委托:先让parent类加载器试图加载该Class
缓存机制:缓存机制会保证所有加载过的Class都会被缓存,当程序需要使用某个Class时,类加载器先从缓存区找,当缓存区不存在该Class对象,系统才会读取该类对应的二进制数据,转换成Class对象,存入缓存区。这也就是为什么修改了Class,不许重新启动JVM,程序新修改才会生效。
这个例子可以获取根类加载器的核心类库:
1 | public class ClassLoaderPropTest { |
打印结果:
1 | 系统类加载器:sun.misc.Launcher$AppClassLoader@18b4aac2 |
Extension Classloader被称为扩展类加载器,负责加载JRE的拓展目录中JAR包的类
从上面结果可以看出,系统类加载器的家在路径是当前程序运行路径,拓展类加载器的加载路径是jdk路径,但是拓展类加载器的父加载器是null,说明并不是根类加载器。
最后总结一下类加载器加载Class的步骤
- 检测Class是否再如果,如果有-> step 8
- 如果父类加载器不存在-> step 4,如果父类加载器存在-> step 3
- 请求使用父类加载器去载入Class,成功-> step 8,失败-> step 5
- 请求使用跟雷加载器载入Class,成功-> step 8,失败-> step 5
- 当前类加载器尝试寻找Class文件,找到-> step 6,失败-> step 7
- 从文件中载入Class,成功-> step 8
- 抛出ClassNotFound异常
- 返回java.lang.class对象
3.通过反射查看类信息
获得Class对象
由于每个类被加载后,系统都会生成一个对应的Class对象,通过该Class对象就可以访问到JVM中的这个类,获得Class对象的方式如下:
- 使用Class类的forName(String clazzName)方法,参数是某个类的全限定类名
- 使用某个类的class属性获取对应的Class对象,例如:Person.class
- 使用某个对象的getClass(0方法
从Class中获取信息
大致包含了以下几个方法:
- Constructor
getConstructor(Class<?>…parameterTypes):返回指定构造器 - Constructor<?>[] getConstructors():返回此类所有构造器
- Method getMethod(String name,Class<?>…parameterTypes):返回指定方法
- Method[] getMethods():返回此类所有public方法
- Field getField(String name):返回此类指定Field
- Field{} getFields():返回此类所有public Field
- …
4.利用反射生成并操作对象
创建对象
通过反射来生成对象有以下两种方式:
- 使用Class对象的newInstance()方法
- 先使用Class对象获取指定的Constructor对象,在调用Constructor对象的newInstance()方法。
举个例子:
1 | private Object createObject(String className) throws ClassNotFoundException, IllegalAccessException, InstantiationException { |
调用方法
生成对象后,就可以通过getMethod()方法或者getMethods()方法来获取方法。
再通过invoke()方法来执行
访问属性值
通过getFields()或者getField()方法可以获取Class对象的Field。可以用以下两组方法来读取或者设置Field值
- getXxx(Object obj):获取Field的属性值
- setXxx(Object obj, Xxx val):将obj对象的Field设置成val值