类加载器调用了许多Java虚拟机中其他的部分和java.lang包中的很多类。比如,类加载对象就是java.lang.ClassLoader子类的实例,ClassLoader类中的方法可以访问虚拟机中的类加载机制;每一个被Java虚拟机加载的类都会被表示为一个java.lang.Class类的实例。像其他对象一样,类加载器对象和Class对象都保存在堆中,被加载的信息保存在方法区中。
1、加载、连接、初始化(Loading,Linking and Initialization)
类加载子系统不仅仅负责定位并加载类文件,他按照以下严格的步骤作了很多其他的事情:
1)、加载:寻找并导入指定类型(类和接口)的二进制信息
2)、连接:进行验证、准备和解析
①验证:确保导入类型的正确性
②准备:为类型分配内存并初始化为默认值
③解析:将字符引用解析为直接饮用
3)、初始化:调用Java代码,初始化类变量为合适的值
2、原始类加载器(The PrimordialClass Loader)
每个Java虚拟机都必须实现一个原始类加载器,他能够加载那些遵守类文件格式并且被信任的类。但是,Java虚拟机的规范并没有定义如何加载类,这由 Java虚拟机实现者自己决定。对于给定类型名的类型,原始莱加载器必须找到那个类型名加“.class”的文件并加载入虚拟机中。
3、类加载器对象
虽然类加载器对象是Java程序的一部分,但是ClassLoader类中的三个方法可以访问Java虚拟机中的类加载子系统。
1)、protected final ClassdefineClass(…):使用这个方法可以出入一个字节数组,定义一个新的类型。
2)、protected ClassfindSystemClass(String name):加载指定的类,如果已经加载,就直接返回。
3)、protected final voidresolveClass(Class c):defineClass()方法只是加载一个类,这个方法负责后续的动态连接和初始化。
4、命名空间
当多个类加载器加载了同一个类时,为了保证他们名字的唯一性,需要在类名前加上加载该类的类加载器的标识。具体的信息,参见第八章“连接模型”( The Linking Model)。
为了更好的了解类加载的过程,我们一起来看看下面的案例吧!
案例1:
class Singleton{
private static Singleton singleton=new Singleton ();
public static int count1;
public static int count2=0;
private Singleton(){
System.out.println("12345");
count1++;
count2++;
}
static{
System.out.println("efefewferfte");
count1++;
count2++;
}
public static SingletongetInstance(){
return singleton;
}
}
public class MyTest{
public static void main(String[]args){
System.out.println("count1="+ Singleton.count1);
System.out.println("count2="+ Singleton.count2);
}
}
案例2:
class Singleton1{
public static int count1;
public static int count2=0;
private static Singleton1 singleton=new Singleton1();
private Singleton1(){
System.out.println("构造方法...");
count1++;
count2++;
}
public static Singleton1getInstance(){
return singleton;
}
static{
System.out.println("静态方法...");
}
}
public class MyTest1{
public static void main(String[]args){
System.out.println("count1="+ Singleton1.count1);
System.out.println("count2="+ Singleton1.count2);
}
}
案例3:
class FinalTest1{
public static final int count=6/3;
static{
System.out.println("静态块"+count);
}
private FinalTest1(){
System.out.println("构造方法:"+count);
}
}
public class MyTest2{
public static void main(String[]args){
System.out.println("count1="+ FinalTest1.count);
}
}
案例4:
class FinalTest2{
public static final int count=newRandom().nextInt(100);
static{
System.out.println("静态块");
}
private FinalTest2(){
System.out.println("构造方法");
}
}
public class MyTest3{
public static void main(String[]args){
System.out.println("count1="+ FinalTest2.count);
}
}
乍一看,好像案例1和案例2,案例3和案例4没什么很大的区别,但结果小伙伴们预料到了吗?想想为什么会这样呢?
参考:http://blog.csdn.net/witsmakemen/article/details/28600127