类生命周期
类加载器
类加载器负责加载、验证、准备和解析步骤,但不会执行静态初始化,搜索网络、jar、zip、文件夹、内存指定位置的二进制类资源。一个Java程序运行,最少有三个类加载器实例,负责不同类的加载。
- Bootstrap ClassLoader:启动类库加载器,负责加载核心类库,由C/C++实现,没有对应的Java类,加载jre/lib目录和用户自己配置的目录,可使用Launcher.getBootstrapClassPath()查看
- Extension ClassLoader:扩展类库加载器,ExtClassLoader实例,负责加载Java扩展类库jre/lib/ext目录和用户自己配置的目录java.ext.dirs
- Application ClassLoader:应用程序类加载器,AppClassLoader实例,可以通过ClassLoader.getSystemClassLoader()方法获取,因此也被称为系统类加载器,加载java.class.path指定的路径,一般情况下我们用的就是这个类加载器
可以通过java.lang.Class.getClassLoader获取类加载器实例,如果是核心类库加载器,返回null。
类的卸载
类的卸载需要满足两个条件:
- 该类的所有实例都被GC回收
- 该类的类加载器也被GC回收
可以通过jvm的启动参数-verbose:class输出类的加载卸载日志
类的唯一性
在Java中,类的唯一性是由类加载器和类本身两者共同确定的,同一个类加载器加载相同包下的同名类代表类相同,相同的类不会重复加载。
双亲委派模型
由于类加载器的多样性,为了避免重复加载,采用了一种由下至上逐级委托,由上至下逐级查找的模型。类加载器不会首先自己去加载类,而是把加载的请求委派给父加载器,每个层级的加载器都是如此,因此最先尝试加载类的一定是启动类库加载器。只有当父加载器的路径无法搜索到类时,子加载器才会尝试自己去加载。这里的父加载器不是继承的父类关系,而是逻辑上的关联,由parent属性指定。