java类加载机制及双亲委托---论HelloWorld

      近期对java类加载机制及双亲委托加载,这个专题进行学习,下面开始进行正题:

     一、类加载机制

    简单的说就是jvm再什么时候将class文件装入自己的内存。开始学java的同学都写过helloWorld,helloword怎么再电脑屏幕上打印,一般步骤就是 javac  HelloWorld.java 生成HelloWorld.class的文件,然后java HelloWorld 运行程序,打印字符串。java HelloWord就会启动jvm,然后装载HelloWorld.class文件,加载HelloWord的class,然后运行。

     基于这个背景,我们来讨论类加载机制。

    根据官方文档表述,java的类加载体系的结构如下:

    1.、根节点接在器 BootstrapClassLoad,主要加载jdk目录下的rt.jar包中的class类,可以通过下面代码打印哪些是由根加载器加载的jar。

URL[] urls = sun.misc.Launcher.getBootstrapClassPath().getURLs();
for(URL url : urls){
    System.out.println(url.toExternalForm());
}

  我本地电脑jdk是1.8.0,输出的是:

file:/C:/Program%20Files/Java/jdk1.8.0_144/jre/lib/resources.jar
file:/C:/Program%20Files/Java/jdk1.8.0_144/jre/lib/rt.jar
file:/C:/Program%20Files/Java/jdk1.8.0_144/jre/lib/sunrsasign.jar
file:/C:/Program%20Files/Java/jdk1.8.0_144/jre/lib/jsse.jar
file:/C:/Program%20Files/Java/jdk1.8.0_144/jre/lib/jce.jar
file:/C:/Program%20Files/Java/jdk1.8.0_144/jre/lib/charsets.jar
file:/C:/Program%20Files/Java/jdk1.8.0_144/jre/lib/jfr.jar
file:/C:/Program%20Files/Java/jdk1.8.0_144/jre/classes

比很多文章中说的多,不仅包括rt.jar,还包括jre下的所有classes文件(本地没有,是空的),java的一些核心类,如system,java.lang下的类都在这里加载

 2、扩展类加载器 ,Extension ClassLoader,主要加载%JAVA_HOME%/jre/ext目录下的jar,这里应该是java为后续可扩展性及后续开发者的便捷度考虑的,在核心区域外,增加扩展类加载。我本地扫了下,jdk8里系统没有预置的jar包。

3.System ClassLoader(或Application ClassLoader):系统(应用)类加载器。一般是本地配置的classpath路径下的jar包或者类文件。参考网上的jdk安装配置教程,大部分如我的小白,这里配置的应该都是tools.jar ,这个jar包里是一下jvmstat的工具类,还有一些asm的包,可以用反编译工具看一下。一般我们在代码中getClassLoader.getName() 返回的都是这个加载器,是日常中运用最频繁的一个加载器。可以说,你政策在ide,eclipse等开发工具中写的java代码,一般都是通过这个加载器加载。

4、自定义加载器,通过继承系统(应用)类加载器,我们也可以根据需要定制属于自己的加载器,这个我从业以来一直没有遇到过这种场景,但是java作为一个成熟的语言是支持这种玩法的,有需要的童鞋可以试一下。

好了,综上所述,我们说清楚了java类加载器的模式。先是根节点加载器,加载一些核心的jar包和类,然后对于扩展类的(java给自己和开发人员留的buffer)使用扩展类加载器,日常我们设置的classpath及编写的代码都是通过系统(应用)类加载器加载的,当然还有些小伙伴们自己写了自定义的加载器,这个就不赘述了。具体的

二、双亲委托

  上面所了一大坨,哪个加载器干啥之类的,其实还有个比较重要的特性就是双亲委派模式。我们继续拿HelloWorld.java举例。我们生成HelloWorld.class文件了,然后调用java HelloWorld执行。jvm怎么找到HelloWorld的class,然后转换成二进制执行呢?

   首先,jvm会在系统类加载器(应用类)加载器去找,如果找不到,在这个里就调用parent去找(扩展类),parent找不到,就到parent的parent去找(也就是根加载器),盗图如下:

java类加载机制及双亲委托---论HelloWorld_第1张图片

从图上来说就比较容易理解了。至于为什么要用这个模式,也很简单。一个是避免浪费,计算机资源有限,如果父类加载过了直接用就行了。一个是安全,保护java的核心类不被用户破坏,比如你自己写了个String 类,包名跟jdk一样,按照双亲委派的模式,系统都懒得搭理你,你也不会对大家造成什么影响。

 

三、论HelloWorld的运行过程

    按照国际惯例,我们写了个HelloWorld.java,然后再javac编译,java命令运行,一般jvm要有一下几个动作。先上代码:

public class HelloWorld {
    public static String str ="Hello World";
    public static void main(String [] args) {
        System.out.println(str);
    }
}

好了,我们通过javac生成HelloWorld.class

1、调用java命令后,jvm开始加载 HelloWorld.class文件到内存。

2、jvm校验HelloWorld.class文件是否合法,如开头是否有魔数caffebabe等

3、准备,为类变量,代码中str ,分配内存并赋初值 str = null

4、解析,官方说法是将字符引用转为直接引用,即代码中将str 编程0xabcdXXX 的地址表示符

5、初始化,给讲台类型初始化。即将str = "HelloWorld"

 

你可能感兴趣的:(学习)