类加载过程与反射
1 类的加载、连接与初始化
1.1 类加载过程
当程序使用某一个类时,如果这个歌类还未被加载到内存中,则系统会通过加载、连接、初始化的步骤来对该类进行初始化。一般类加载器无需等到首次使用时再加载对象,java虚拟机允许虚拟机预先加载某些类。
类加载: 将类的class文件读如内存,并为之创建一个java.lang.Class对象。即当程序使用任何类时,系统都会为其建立一个java.lang.Class对象。
1.1.1 加载 loading
class加载到内存,该过程由加载器完成,过程是双亲委派机制,
1.1.2 连接 linking
当类被加载之后,系统为之生成一个对应的Class对象,接着会进入连接阶段,连接阶段负责把二进制数据合并大JRE中。连接过程分为如下三个阶段:
- verification:校验文件是否符合JVM的规定
- preparation:静态成员变量赋默认值
- resolution:
将类、方法、属性等符号引用解析为直接引用;
将常量池中的各种符号引用解析为指针、偏移量等内存地址的直接引用;
1.1.3 初始化 intialization
到了初始化阶段才开始真正执行类中定义的java代码。该阶段调用初始化代码,将静态变量赋初始值。
赋值过程
load -> 默认值 -> 初始值
new -> 申请内存 -> 赋默认值 -> 赋初始值
1.2 类加载器
类加载器负责将.class文件加载到内存中,并生成与之对应的java.lang.Class对象。
1.2.1 加载器分类
- 启动类加载器:Bootstrap ClassLoader,它负责加载
JAVA_HOME\lib
中的或通过-Xbootclasspath
参数指定路径中的或系统值指定的类。 - 扩展类加载器:Extension ClassLoader,它负责加载
JAVA_HOME\lib\ext
目录中的,或通过java.ext.dirs
参数指定路径中的类。 - 系统类加载器:System ClassLoader,它负责加载用户路径上的类。
- 用户自定义类加载器
JVM通过双亲委派模型进行类的加载。
1.2.2 类加载机制
- 全盘委托: 当一个类加载器负责加载某个Class时,该Class引用和依赖的其他Class也将有该类加载器负责加载,除非显示使用另外一个加载器载入。
- 父类委托: 先让parent类加载器尝试加载该Class,只有在父类加载器无法加载到该类时才会尝试从自己的加载路径中加载该Class。
- 缓存机制: 保证所有加载过的Class都会被缓存,当程序需要某个Class时,先从缓存中获取,当缓存中不存在该Class对象时,系统才会读取该类对应的二进制文件并将其转换成Class对象,存入缓存中。
2 反射
2.1 获取class对象
获取Class有三种方式:
- 使用
Class.forName("类的全路径")
; - 使用
对象.getClass()
方法获取; - 调用某个类的class属性获取对应的Class对象.
2.3 创建对象
使用反射来生成对象有两种方式:
- 使用
Class
对象的newInstance()
方法创建该Class对象对应的实例(这种方式要求该Class对象对应类默认构造器); - 先使用
Class
对象获取指定的Consrtuctor
对象,再调用Constructor
对象的newInstance()
方法来创建该Class
对象的对应实例。
/**
* @author : wind-myf
* @desc : 对象池工厂
* @version : 1.0
*/
public class ObjectPoolFactory {
/**
* 定义一个map存储对象,key-对象名,value-对象
*/
private static Map<String,Object> objectMap = new HashMap<>();
/**
* 工厂初始化
* 读取文件
*/
public void initFactory(String fileName) {
// 读取文件内容
FileInputStream fileInputStream = null;
try {
fileInputStream = new FileInputStream(fileName);
Properties properties = new Properties();
properties.load(fileInputStream);
// 循环创建对象
for (String name : properties.stringPropertyNames()) {
objectMap.put(name,createObject(properties.getProperty(name)));
}
} catch (IOException | IllegalAccessException | InstantiationException | ClassNotFoundException e) {
e.printStackTrace();
System.out.println("读取文件异常,文件名称为:" + fileName);
}
}
/**
* 根据对象全名利用反射创建对象
* 并存入map中
* @param className 类全名
*/
private Object createObject(String className) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
// 获取class对象
Class<?> clazz = Class.forName(className);
return clazz.newInstance();
}
/**
* 对象获取
*/
public Object getObject(String className){
return objectMap.get(className);
}
public static void main(String[] args) {
ObjectPoolFactory objectPoolFactory = new ObjectPoolFactory();
// 此处需绝对路径
objectPoolFactory.initFactory("src/main/java/com/myf/wind/base/reflectdemo/object.txt");
Object drum = objectMap.get("drum");
System.out.println("drum = " + drum);
Object guitar = objectMap.get("guitar");
System.out.println("guitar = " + guitar);
}
}
2.4 基于反射实现jdk动态代理(AOP实现)
jdk动态代理是通过Proxy
类与InvocationHandler
接口生成jdk动态代理类和动态代理对象。以下示例中MyProxyFactory
通过反射获取代理类,自定义MyInvocationHandler
中实现方法拦截,在方法拦截前后执行自定义的拦截方法。
AOP实现示例:
/**
* @author : wind-myf
* @desc : JDK动态代理
*/
public class JdkProxyDemo {
public static void main(String[] args) {
Flower target = new FlowerImpl();
Flower flower = (Flower)MyProxyFactory.getProxy(target);
flower.sayFlowering("春季");
flower.queryColors();
}
}
/**
* 代理类工厂
*/
class MyProxyFactory{
/**
* 获取代理类
*/
public static Object getProxy(Object target){
MyInvocationHandler handler = new MyInvocationHandler();
handler.setTarget(target);
return Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(), handler);
}
}
/**
* 鲜花接口
*/
interface Flower {
void sayFlowering(String season);
List<String> queryColors();
}
/**
* 实现类
*/
class FlowerImpl implements Flower{
@Override
public void sayFlowering(String season) {
System.out.println("this is beautiful season : " + season);
}
@Override
public List<String> queryColors() {
System.out.println("this is queryColors-----");
List<String> colors = new ArrayList<>();
colors.add("green");
colors.add("red");
colors.add("blue");
return colors;
}
}
class MyInvocationHandler implements InvocationHandler{
/**
* 需要被代理的对象
*/
private Object target;
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 在执行原方法前执行方法1
FlowerUtil.flowerMethod1();
Object result = method.invoke(target, args);
// 在原方法执行完成后执行拦截方法二
FlowerUtil.flowerMethod2();
return result;
}
public void setTarget(Object target) {
this.target = target;
}
}
/**
* 拦截方法工具类
*/
class FlowerUtil{
/**
* 拦截方法一
*/
public static void flowerMethod1(){
System.out.println("FlowerUtil--method 1------");
}
/**
* 拦截方法二
*/
public static void flowerMethod2(){
System.out.println("FlowerUtil--method 2------");
}
}
3 备注
以上代码demo
git地址:
https://github.com/windmyf/study-demo/blob/main/base-demo/src/main/java/com/myf/wind/base/reflectdemo/JdkProxyDemo.java