《疯狂Java讲义(第4版)》-----第18章【类的加载机制与反射】
JVM进程终止的情况程序运行到最后正常结束程序运行到System.exit()或Runtime.getRuntime().exit()程序执行过程中遇到未捕获的异常或错误而结束程序所在平台强制结束了JVM进程类的加载下图摘自《深入理解Java虚拟机:JVM高级特性与最佳实践》类加载:将类的class文件读入内存,并为之创建一个java.lang.Class对象。类加载过程由类加...
JVM进程终止的情况
- 程序运行到最后正常结束
- 程序运行到System.exit()或Runtime.getRuntime().exit()
- 程序执行过程中遇到未捕获的异常或错误而结束
- 程序所在平台强制结束了JVM进程
类的加载
下图摘自《深入理解Java虚拟机:JVM高级特性与最佳实践》
类加载:将类的class文件读入内存,并为之创建一个java.lang.Class对象。类加载过程由类加载器完成。
类加载器无须等到“首次使用”某类时才加载该类,Java虚拟机规范允许系统先加载某些类。
类的连接
连接阶段负责把类的二进制数据合并到JRE中。
(1)验证
(2)准备:为类变量分配内存,设置默认值
(3)解析:把类的二进制数据中的符号引用替换成直接引用
类的初始化
什么情况会导致类的初始化?
(1)创建类的实例。new一个实例,反射创建实例,反序列化创建实例
(2)调用类方法(静态方法)
(3)访问某个类或接口的类变量,或为该类变量赋值
(4)使用发射方式强制创建某个类或接口对应的java.lang.Class对象
(5)初始化某个类的子类
(6)直接使用java.exe命令允许某个主类。
调用final修饰的类变量(编译时已经确定下来)—不会进行类初始化,没调用初始化块
class Test{
static{
System.out.println("静态初始化块。。。");
}
public static final String s = "我是静态常量,编译时已确定,我类的静态初始化块没调用吧哈!";
}
public class Main{
public static void main(String[] args){
System.out.println(Test.s);
}
}
调用final修饰的类变量(编译时未确定下来)—会进行类初始化,调用了初始化块
class Test{
static{
System.out.println("静态初始化块。。。");
}
public static final String s = "我是静态变量,编译时没确定,我类的静态初始化块要调用吧哈!"+ System.currentTimeMillis();
}
public class Main{
public static void main(String[] args){
System.out.println(Test.s);
}
}
类加载机制
一个类被加载后就不会再次被加载了。
三种类加载机制:
(1)全盘负责
(2)父类委托
(3)缓存机制:所有加载过的Class都会被缓存,当程序需要使用某个Class时,类加载器先从缓冲区找,找不到才会读二进制数据,转成Class对象,并存入缓冲区。
反射
获得Class对象
方式一:
方式二:
类名.class
方式三:
对象.getClass()
动态代理
JDK动态代理只能为接口创建动态代理对象。
动态代理是AOP的基础。动态代理实现了:既可以完成某类的某个方法的调用,同时可以在这个调用方法的前后加入一些想加入的代码。动态代理实现了方法增强,还可以重用代码(当多个方法都需要调用某一段代码的时候,可以把共同的代码抽取出来,放到InvocationHandler实现类的invoke方法的前后)。
【示例代码】
(改造《疯狂Java讲义(第4版)》859~862页代码)
import java.lang.reflect.*;
interface A{
public void fun1(int a);
public void fun2(int a, int b);
public void fun3();
}
class B implements A{
public void fun1(int a){
System.out.println("aaaaaaaaa");
}
public void fun2(int a, int b){
System.out.println("abababab");
}
public void fun3(){
System.out.println(333333333);
}
}
class MyInvocationHandler implements InvocationHandler {
private Object target;//这个就是被代理的对象,因为JDK动态代理只能为接口代理,那就让这个对象实现接口
public void setTarget(Object target){
this.target = target;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Exception{
//调用method.invoke()之前(即调用目标方法之前),可以加入代码放在这里
System.out.println("拦截器代码/公共代码---前置目标方法调用前");
Object result = method.invoke(target, args);//这是调用目标对象target的method方法,method的参数列表是args
//调用method.invoke()之后(即调用目标方法之后),可以加入代码放在这里
System.out.println("拦截器代码/公共代码---后置目标方法调用后");
System.out.println();
return result;
}
}
public class Main{
public static void main(String[] args){
MyInvocationHandler handler = new MyInvocationHandler();
A target = new B();
handler.setTarget(target);
A proxy = (A)Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), handler);
proxy.fun1(1);
proxy.fun2(1, 2);
proxy.fun3();
}
}
更多推荐
所有评论(0)