您的位置:首页 > 编程语言 > Java开发

java类加载过程

2017-04-08 12:49 260 查看
.java文件---(编译)-->.class文件(字节码文件)--->(jvm解释)---->二进制机器码

jvm类加载过程为:

1,装载,查找和导入Class文件.

2,链接:

    1,验证,确保Class文件中的二进制信息符合当前虚拟机的要求。

    2,准备:为类变量分配内存并设置类变量初始值( 这时候分配内存和初始化的仅是static变量,实例变量需要在类加载时分配在java堆中)。

    3,解析:将常量池中的符号引用替换成直接引用。(简单来说,符号引用就是字符串,包含类的相关信息,凭借此可以找到相应的位置,直接引用就是偏移量,通过直接引用可以直接在内存区域中找到字节码起始位置)

3,类初始化

准备阶段和初始化阶段并不矛盾,如果类中有语句:private static int a = 10,它的执行过程是这样的,首先字节码文件被加载到内存,然后进行链接的验证,验证通过后在方法区内给a分配内存,并初始化为0,然后解析,在初始化时,才把10赋给a,此时a=10。

类的加载的双亲委派模型: 

类的加载指的是将类的class文件中的二进制数据读入到内存中,将其放在方法区内,然后在java堆区创建一个这个类的Java.lang.Class对象,用来封装类在方法区类的对象.

 流程:

 1, 产生一个Bootstrap Loader类.

 2,Bootstrap自动加载Extended Loader,并将其父Loader设为Bootstrap Loader。

 3,Bootstrap自动加载AppClass Loader(系统加载器),并且将其父Loader设为Extended Loader.

 4,由AppClass Loader加载该类.

双亲委培模型:就是类接到加载类的请求时,首先将加载任务委托给父类加载器,依次递归,如果父类加载器可以完成类加载任务,就成功返回;只有父类加载器无法完成此加载任务时,才自己去加载。

双亲委派模型的意义:

使得类加载器具有层次结构,所有相同的类在各种类加载器环境中都是同一份字节码.

  

public class HelloWorld {
public static void main(String[] args) {
HelloWorld hello=new HelloWorld();
Class c=hello.getClass();
System.out.println(c);//HelloWorld类
ClassLoader loader=c.getClassLoader();
System.out.println(loader);//AppLoader类
System.out.println(loader.getParent());//Extended Loader类
System.out.println(loader.getParent().getParent());//BootStrap类(因为是用c写的,所以找不到返回方式)
}
}


自定义类加载器没有指定父类加载器的情况下,默认的父类加载器即为系统类加载器(实现类为AppClass Loader)

能不能自己写个类叫java.lang.System?

不行。爸爸们能找到的类,儿子就没有机会加载,而System类是Bootstrap加载器加载的,就算自己重写,也总是使用系统提供的System,自己写的System类根本没有机会得到加载。http://blog.csdn.net/tang9140/article/details/42738433

  

class SingleTon {
private static SingleTon singleTon = new SingleTon();
public static int count1;
public static int count2 = 0;

private SingleTon() {
count1++;
count2++;
}

public static SingleTon getInstance() {
return singleTon;
}
}

public class Test2 {
public static void main(String[] args) {
SingleTon singleTon = SingleTon.getInstance();
System.out.println("count1=" + singleTon.count1);
System.out.println("count2=" + singleTon.count2);
}
}


错误答案

count1=1

count2=1

正确答案

count1=1

count2=0

分析:

1:SingleTon singleTon = SingleTon.getInstance();调用了类的SingleTon调用了类的静态方法,触发类的初始化

2:类加载的时候在准备过程中为类变量分配内存并初始化默认值 singleton=null ,count1=0,count2=0

3:类初始化化,为类的静态变量赋值和执行静态代码快。按照顺序   singleton赋值为new SingleTon()调用类的构造方法

4:调用类的构造方法后count=1;count2=1

5:继续为count1与count2赋值,此时count1没有赋值操作,所有count1为1,但是count2执行赋值操作就变为0

如果我们修改代码:

class SingleTon {
public static int count1;
public static int count2 = 0;
private static SingleTon singleTon = new SingleTon();
private SingleTon() {
count1++;
count2++;
}

public static SingleTon getInstance() {
return singleTon;
}
}

public class Test2 {
public static void main(String[] args) {
SingleTon singleTon = SingleTon.getInstance();
System.out.println("count1=" + singleTon.count1);
System.out.println("count2=" + singleTon.count2);
}
}


count1=1

count2=1
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: