Java类加载机制

类加载子系统

1. 类加载子系统分为三个阶段:装载,连接(验证,准备,解析),初始化

装载 :将class文件读入内存中,并生成这个class文件的Class类对象(由后面将会说 到的类加载器完成这个装载过程)

连接:

验证:验证class文件的正确性安全性等

准备:为类的静态变量分配内存,并将其初始化为默认值

解析:将类中的符号引用转为直接引用(将a.method()这种符号引用转为method 代码的入口地址这种直接引用)(多态在这一步被确定下来,比如Father f = new Son(); 那么f.method()调用的是父类的method还是子类的method 在这一步它就会看f对象到底是Father类还是Son类,这里是Son类,所 以会调用子类的method)

初始化:按先后顺序运行static代码块以及程序中对静态变量的赋值操作,将静态变量 赋值为程序指定的初始值

2. Java中,上面说的所有阶段都是在运行期间完成的而不是编译期(正因为如此,Java的反射机制才能够在运行中动态的创建某个类的对象)

3. 初始化阶段的时机:

仅当对类进行主动使用的时候,才会触发类的初始化阶段的进行。主动使用有:创建类的实例,访问类的静态变量静态方法,反射(Class.forName),主动使用了该类的子类(但主动使用子接口中的静态常量并不会触发父接口的初始化),以及提供给动态语言的支持(暂不管)。除了以上情况,其余都为被动使用,不会触发初始化

对于访问类的静态变量静态方法的进一步解释:

调用Son.father_static_attr不会触发Son类初始化,只会触发Father类初始化

调用System.out.println(Son.final_static_attr)在编译时该代码会被替换为

System.out.println(10),所以运行时跟Son没有任何关系,但如果final_static_attr=new A()这种需要在运行期才能确定的东西,编译期就没办法替换。

4. 装载和连接的时机:

虚拟机可以在某个类被主动使用之前,就提前把该类加载和连接了,而Java虚拟机规范中并没有明确的规定加载和连接的具体时机,所以不同的虚拟机可以对其有不同的实现。我们可以通过在运行代码使添加-XX:+TraceClassLoading打开类加载器追踪,让其输出类加载的情况。

5. 类加载器:

共有如下四种:

根类加载器(Bootstrap):该加载器不是由Java实现的。用于加载位于JAVA_HOME/jre/lib下的特定的类

扩展类加载器:纯Java类,它继承自ClassLoader类。用于加载位于JAVA_HOME/jre/lib/ext下的类

系统加载器(App ClassLoader):纯Java类,它继承自ClassLoader类。用于加载位于classpath环境变量所指定路径下的类

用户自定义加载器:需要继承ClassLoader类

 

 

 

 

双亲(父亲)委派机制:

 

 

根类加载器是扩展类加载器的父加载器,扩展类加载器是应用类加载器的父加载器,应用类加载器默认是我们自己定义的加载器的父加载器。当指定某个类加载器去加载某个类时

,会看该类加载器有没有父加载器,有的话就自己先不去加载,而是委派自己的父加载器去加载,直到根类加载器为止(即从下往上委派)。然后从根类加载器开始从上往下去尝试加载该类,如果根类加载器加载不了(比如该类不是位于JAVA_HOME/jre/lib下的特定的类),则交回给扩展类加载器加载,若它也加载不了,则继续往下传,直到有某个类加载器成功加载,不然则报错。

(注:这里的父子关系并不是Java中的继承关系,而是双亲委派机制中的父子关系)

 

类的装载过程:

 

这里通过Temp去拿到了系统类加载器,然后用系统类加载器去装载类A。loadClass方法(该方法就是双亲委派机制的实现)首先会去看类A是否已经被自己装载过,如果已经被装载过了则直接返回对应的Class对象,否则则去调用父加载器的loadClass方法,父加载器也同样去查看自己是否已装载过该类...直到根类加载器,根类加载器如果已经装载过该类则返回对应的Class类对象,如没有则尝试去装载这个类,如果失败则返回null给扩展类加载器,扩展类加载器则会调用自己的findClass方法,该方法负责将该类的class文件读取进来转为byte[]类型,并且以该byte数组为参数去调用defineClass方法,defineClass方法则会去解析这个byte数组,转化成Class对象返回。那么如果findClass方法没能成功找到或者解析这个class文件,则同样是返回null给下一层加载器,依次类推。最后拿到Class对象或者依旧为空则抛出异常。

如果想要实现自己的类装载器,则去继承ClassLoader类,然后去覆盖findClass和defineClass方法,以自己的方式去读取和解析字节码。

 

双亲委派机制的优点:双亲委派机制自下而上的过程保证了核心类无法被重复加载;自上而下的过程保证了核心类总是优先被高级别的类加载器加载。

(对于由自定义类加载器加载的类,其可以被不同的自定义类加载器重复加载,即在虚拟机中,该类的Class对象可以有多个。这是因为自定义类加载器之间可以不存在父子关系,双亲委派机制无法在它们之间起作用)

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值