[size=medium][b][color=indigo]Java 的 Class 加载 步骤[/color][/b][/size]
[size=medium][b]一、背景知识[/b][/size]
[b]1. java.lang.ClassLoader类介绍[/b]
<Abstract> java.lang.ClassLoader
java.lang.ClassLoader 类的基本职责就是根据一个指定的类的名称,找到其对应的二进制字节代码文件。
然后根据这个文件,生成一个 java.lang.Class 类的实例。
[color=green]- part of methods in java.lang.ClassLoader[/color]
[b]2. JVM中类加载器的树状层次结构[/b]
1) 引导类加载器(bootstrap class loader):
它用来加载 Java 的核心库(jre/lib/rt.jar)。
是用原生C++代码来实现的,并不继承自java.lang.ClassLoader。
2) 扩展类加载器(extensions class loader) :继承自 1)
它用来加载 Java 的扩展库(jre/ext/*.jar)。
Java 虚拟机的实现会提供一个扩展库目录。该类加载器在此目录里面查找并加载 Java 类。
3) 系统类加载器(system class loader):继承自 2)
它根据 Java 应用的类路径(CLASSPATH)来加载 Java 类。
一般来说,Java 应用的类都是由它来完成加载的。
可以通过 java.lang.ClassLoader.getSystemClassLoader()来获取它。
除了系统提供的类加载器以外,开发人员可以通过继承
java.lang.ClassLoader类的方式实现自己的类加载器,以满足一些特殊的需求。
[b]3. 双亲委派机制[/b]
某个特定的类加载器在接到加载类的请求时,首先将加载任务委托交给父类加载器。
父类加载器又将加载任务向上委托,直到最父类加载器。
如果最父类加载器可以完成类加载任务,就成功返回。
如果不行就向下传递委托任务,由其子类加载器进行加载。
双亲委派机制的好处:
保证java核心库的安全性。
例如:
如果用户自己写了一个java.lang.String类就会因双亲委派机制不能被加载,
不会破坏原生的String类的加载。
[size=medium][b]二、类加载过程[/b][/size]
JVM将类加载过程分为三个步骤:
[b]1) 装载(Load):[/b]
查找并加载类的二进制数据。
[b]2) 链接(Link):[/b]
语法验证:确保被加载类信息符合JVM规范、没有安全方面的问题。
准备:为类的静态变量分配内存,并将其初始化为默认值。
解析:把虚拟机常量池中的符号引用转换为直接引用。
Java 中,虚拟机会为每个加载的类维护一个常量池。
【不同于字符串常量池,这个常量池只是该类的字面值(
例如:类名、方法名)和符号引用的有序集合。
而字符串常量池,是整个JVM共享的】
这些符号(如int a = 5; 中的 a )就是符号引用,
而解析过程就是把它转换成指向该类在堆中生成的对象地址的相对地址。
[b]3) 初始化(Initialize):[/b]
为类的静态变量赋予正确的初始值。
步骤:
1>. 如果这个类还没有被加载和链接,那先进行加载和链接。
2>. 假如这个类存在直接父类,并且该父类还没有被初始化(
注意:在一个类加载器中,类只能初始化一次),
那么先初始化其直接的父类(不适用于接口)
3>. 如果类中存在 static 语句块,那就依次执行这些初始化语句。
-
引用:
- 全面解析Java类加载器
[url]http://www.cnblogs.com/sunniest/p/4574080.html[/url]
-
[size=medium][b]一、背景知识[/b][/size]
[b]1. java.lang.ClassLoader类介绍[/b]
<Abstract> java.lang.ClassLoader
java.lang.ClassLoader 类的基本职责就是根据一个指定的类的名称,找到其对应的二进制字节代码文件。
然后根据这个文件,生成一个 java.lang.Class 类的实例。
[color=green]- part of methods in java.lang.ClassLoader[/color]
// 1.
// get parent class loader.
public java.lang.ClassLoader getParent()
// 2.
// load a class according its binary name,
// return a class instance.
public java.lang.Class<T> loadClass(String name)
// 3.
// Converts an array of bytes into an instance of class Class.
protected final java.lang.Class<T> defineClass(String name, byte[] b, int off, int len)
//
[b]2. JVM中类加载器的树状层次结构[/b]
1) 引导类加载器(bootstrap class loader):
它用来加载 Java 的核心库(jre/lib/rt.jar)。
是用原生C++代码来实现的,并不继承自java.lang.ClassLoader。
2) 扩展类加载器(extensions class loader) :继承自 1)
它用来加载 Java 的扩展库(jre/ext/*.jar)。
Java 虚拟机的实现会提供一个扩展库目录。该类加载器在此目录里面查找并加载 Java 类。
3) 系统类加载器(system class loader):继承自 2)
它根据 Java 应用的类路径(CLASSPATH)来加载 Java 类。
一般来说,Java 应用的类都是由它来完成加载的。
可以通过 java.lang.ClassLoader.getSystemClassLoader()来获取它。
除了系统提供的类加载器以外,开发人员可以通过继承
java.lang.ClassLoader类的方式实现自己的类加载器,以满足一些特殊的需求。
public class TestMClassLoader {
public static void main(String[] args) throws Exception{
//current class loader.
System.out.println(TestMClassLoader.class.getClassLoader());
//application class loader
System.out.println(ClassLoader.getSystemClassLoader());
//extensions class loader
System.out.println(ClassLoader.getSystemClassLoader().getParent());
//bootstrap class loader
System.out.println(ClassLoader.getSystemClassLoader().getParent().getParent());
}
}
/*
output:
sun.misc.Launcher$AppClassLoader@3e0ebb
sun.misc.Launcher$AppClassLoader@3e0ebb
sun.misc.Launcher$ExtClassLoader@39443f
null
*/
/*
可以看出:
ClassLoader 类是由 AppClassLoader 加载的,其父类是 ExtClassLoader 。
ExtClassLoader 的父类无法获取是因为它是用 C++ 实现的。
*/
[b]3. 双亲委派机制[/b]
某个特定的类加载器在接到加载类的请求时,首先将加载任务委托交给父类加载器。
父类加载器又将加载任务向上委托,直到最父类加载器。
如果最父类加载器可以完成类加载任务,就成功返回。
如果不行就向下传递委托任务,由其子类加载器进行加载。
双亲委派机制的好处:
保证java核心库的安全性。
例如:
如果用户自己写了一个java.lang.String类就会因双亲委派机制不能被加载,
不会破坏原生的String类的加载。
[size=medium][b]二、类加载过程[/b][/size]
JVM将类加载过程分为三个步骤:
[b]1) 装载(Load):[/b]
查找并加载类的二进制数据。
[b]2) 链接(Link):[/b]
语法验证:确保被加载类信息符合JVM规范、没有安全方面的问题。
准备:为类的静态变量分配内存,并将其初始化为默认值。
解析:把虚拟机常量池中的符号引用转换为直接引用。
Java 中,虚拟机会为每个加载的类维护一个常量池。
【不同于字符串常量池,这个常量池只是该类的字面值(
例如:类名、方法名)和符号引用的有序集合。
而字符串常量池,是整个JVM共享的】
这些符号(如int a = 5; 中的 a )就是符号引用,
而解析过程就是把它转换成指向该类在堆中生成的对象地址的相对地址。
[b]3) 初始化(Initialize):[/b]
为类的静态变量赋予正确的初始值。
步骤:
1>. 如果这个类还没有被加载和链接,那先进行加载和链接。
2>. 假如这个类存在直接父类,并且该父类还没有被初始化(
注意:在一个类加载器中,类只能初始化一次),
那么先初始化其直接的父类(不适用于接口)
3>. 如果类中存在 static 语句块,那就依次执行这些初始化语句。
-
引用:
- 全面解析Java类加载器
[url]http://www.cnblogs.com/sunniest/p/4574080.html[/url]
-