Java类加载器

类加载器

        一、类加载器的作用

                将Java源程序(.java文件)编译生成的字节码文件(.class文件),然后通过全类名加载到JVM中,也就是在内存中生成一个代表该类的Class对象。

        二、类加载的过程

                类加载过程分为:加载->链接->初始化,其中链接过程具体细分为:验证->准备->解析。

                1、加载:

                        ①通过包名 + 类名,获取这个类,准备用流进行传输;

                        ②将这个类加载到内存中;

                        ③加载完毕后创建一个class对象。

                2、验证:

                        确保Class文件字节流中包含的信息符合当前虚拟机的要求,并且不会危害虚拟机自身安全,文件中的信息是否符合虚拟机规范有没有安全隐患。主要包括四种验证,文件格式验证,元数据验证,字节码验证,符号引用验证。

                3、准备:

                        负责为类的类变量(被static修饰的变量)分配内存,并设置默认初始化值,初始化静态变量。(如static int i=5;这里只将i初始化为0,至于5的值将在下面初始化时赋值)

                4、解析:

                        将类的二进制数据流中的符号引用替换为直接引用,本类中如果用到了其他类,此时就需要找到对应的类。例如:static String name;中的String类型解析是占位符,直接引用则是String的地址值。

                5、初始化:

                        根据程序员通过程序制定的主观计划去初始化类变量和其他资源,静态变量赋值以及初始化其他资源。如前面只初始化了默认值的static变量将会在这个阶段赋值,成员变量也将被初始化

        三、什么时候执行类加载

                ①创建类的实例(对象)

                ②调用类的类方法

                ③访问类或者接口的类变量,或者为该类变量赋值

                ④使用反射方式来强制创建某个类或接口对应的java.lang.Class对象

                ⑤初始化某个类的子类

                ⑥直接使用java.exe命令来运行某个主类

        四、类加载的分类

                ①启动类加载器(Bootstrap class loader):虚拟机的内置类加载器,通常表示为null ,并且没有父null;是用本地代码实现的类装入器,负责加载java的核心类 ,它负责将 JDK的安装目录的jre/lib下面的类库加载到内存中(比如rt.jar)。由于引导类加载器涉及到虚拟机本地实现细节,开发者无法直接获取到启动类加载器的引用,所以不允许直接通过引用进行操作。

                ②平台类加载器(Platform class loader):负责加载JDK中一些特殊的模块,是由 Sun 的ExtClassLoader(sun.misc.Launcher$ExtClassLoader)实现的。它负责JDK的安装目录的jre/lib/ext子目录下(扩展目录)下加载类库。   

                        注:JDK8的类加载器是扩展类加载器,JDK9的类加载器是平台类加载器。这两种类加载器的改变请参考链接:http://t.csdnimg.cn/eNy4L

                ③系统类加载器(System class loader):也称应用程序类加载器(Application class Loader),负责加载用户类路径上所指定的类库,是由 Sun 的AppClassLoader(sun.misc.Launcher$AppClassLoader)实现的。它负责将系统类路径(CLASSPATH)中指定的类库加载到内存中。程序可以通过getSystemClassLoader()来获取系统类加载器。系统加载器的加载路径是程序运行的当前路径。

                注:平常我们的代码都是通过系统类加载器进行加载的,他们之间的继承关系不是通过extends实现的,而是通过逻辑关系。

public class Demo {
    public static void main(String[] args) {
        //获取系统类加载器
        ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();

        //获取系统类加载器的父加载器 --- 平台类加载器
        ClassLoader classLoader1 = systemClassLoader.getParent();

        //获取平台类加载器的父加载器 --- 启动类加载器
        ClassLoader classLoader2 = classLoader1.getParent();

        System.out.println("系统类加载器" + systemClassLoader);//系统类加载器sun.misc.Launcher$AppClassLoader@73d16e93

        System.out.println("平台类加载器" + classLoader1);//平台类加载器sun.misc.Launcher$ExtClassLoader@15db9742

        System.out.println("启动类加载器" + classLoader2);//启动类加载器null

        //输出AppClassLoader。说明对于用户自定义类来说:默认使用系统类加载器进行加载
        ClassLoader classLoader = Demo.class.getClassLoader();
        System.out.println(classLoader);//sun.misc.Launcher$AppClassLoader@73d16e93
    }
}
        五、双亲委派模型

                如果一个类加载器收到了类加载请求,它并不会自己先去加载,而是把这个请求委托给父类的加载器去执行,如果父类加载器还存在其父类加载器,则进一步向上委托,依次递归,请求最终将到达顶层的启动类加载器。

                如果父类加载器可以完成类加载任务,就成功返回;倘若父类加载器无法完成此加载任务,子加载器才会尝试自己去加载,这就是双亲委派模式。

 

                

                双亲委派的好处:避免重复加载 + 避免核心类篡改

                采用双亲委派模式的是好处是Java类随着它的类加载器一起具备了一种带有优先级的层次关系,通过这种层级关可以避免类的重复加载,当父亲已经加载了该类时,就没有必要子ClassLoader再加载一次。

                其次是考虑到安全因素,java核心api中定义类型不会被随意替换,假设通过网络传递一个名为java.lang.Integer的类,通过双亲委托模式传递到启动类加载器,而启动类加载器在核心Java API发现这个名字的类,发现该类已被加载,并不会重新加载网络传递的过来的java.lang.Integer,而直接返回已加载过的Integer.class,这样便可以防止核心API库被随意篡改。

        六、ClassLoader中的两个常用的方法                

变量与类型方法说明
static ClassLoadergetSystemClassLoader()获取系统类加载器
static InputStreamgetResourceAsStream(String name)加载某一个资源文件

  • 23
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值