????? 大家应该还记得我们刚开始学java的时候,都是由记事本开始写代码的吧!这篇博客就从这里开始说起。
???? 我们编写的代码都是纯文本的源程序,它必须经过编译,生成字节码的类文件之后才能运行。类文件是二进制的,没有统一的格式,JVM能识别这样的类文件并执行它,java的编译器是javac,这样编译之后的类文件就可以执行了,JVM再通过java解释器执类文件,这个解释执行过程又分为三部分:代码的装入、代码的校验、代码的执行,其中,代码的装入是由类装载器来完成的,代码的校验是由字节码校验器进行检查,校验完之后就进行执行。
???? 说到这里,先让我们来了解一下java的四大核心技术思想吧!
???? 1、java虚拟机:
?java虚拟机的主要任务是装载class文件并且执行里面的字节码,java虚拟机包含一个类装载器,它可以从程序和API中转载class文件,java API中只有程序需要执行的那些类才会被装载进来。
???? 2、java class文件:
?为java程序提供独立于底层主机平台的二进制形式的服务。
???? 3、类转载器的体系结构:
?一个java应用程序可以运用两种装载器:用户定义的类装载器和启动类装载器,启动类装载器(这是系统中唯一的)是java虚拟机实现的一部分。启动类装载器通常使用某种默认方式从本地磁盘中装载类,包括java API类。
???? 4、java API:
?java API是运行库的集合,它提供了一套访问主机系统资源的标准方法。
????? 有了一些基本了解之后,我们来着重研究一下类加载器。
????? java虚拟机预定义的三种类型的加载器:
???? ?1、启动类加载器(Bootstrap):负责加载<java_Runtime_Home>/lib下面的类库加载到内存中。
????? 2、标准扩展类加载器(Extension):该加载器类是由sun.misc.Launcher$ExtClassLoader实现的,它负责将
<Java_Runtime_Home>/lib/ext里面的类库加载到内存中。
????? 3、系统类加载器(System):该类加载器是由sun.misc.Launcher$AppClassLoader实现的,它负责将系统类路径(CLASSPATH)中的类库加载到内存中。
?????? 我们可以用代码来测试一下这三个主要的类加载器:
?????
package com.netjava0225; import com.sun.crypto.provider.AESCipher; public class TestClassLoad2 { public static void main(String[] args) { System.out.println(String.class.getClassLoader()); System.out.println(AESCipher.class.getClassLoader().getClass().getName()); System.out.println(TestClassLoad2.class.getClassLoader().getClass().getName()); System.out.println(ClassLoader.getSystemClassLoader().getClass().getName()); } }
?
输出的结果是:
null
sun.misc.Launcher$ExtClassLoader
sun.misc.Launcher$AppClassLoader
sun.misc.Launcher$AppClassLoader
?
这里说明一下,因为启动类加载器是java中最核心最基本的类加载器,所以不能那么容易取得其实例化的对象,即为NULL。
?
?
这三类加载器的运行过程其实是双亲委派机制实现加载过程,它们是一层一层的向上递交:
如图所示:
?
?
?
同样我们可以来分析一下ClassLoade的源码:
抽象类ClassLoader部分代码:
?
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException { synchronized (getClassLoadingLock(name)) { // 首先检查类是否被加载 Class c = findLoadedClass(name); if (c == null) { long t0 = System.nanoTime(); try { //查看父类加载器时候已经加载该类 if (parent != null) { c = parent.loadClass(name, false); } else { //查看启动加载器是否加载该类 c = findBootstrapClassOrNull(name); } } catch (ClassNotFoundException e) { // ClassNotFoundException thrown if class not found // from the non-null parent class loader } if (c == null) { //最后才调用自己的加载器进行加载 // If still not found, then invoke findClass in order // to find the class. long t1 = System.nanoTime(); c = findClass(name); // this is the defining class loader; record the stats sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0); sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1); sun.misc.PerfCounter.getFindClasses().increment(); } } if (resolve) { resolveClass(c); } return c; } }
?这样就能很清晰的看到这个过程是怎样进行加载的了,还有什么是动态装载呢?!其实就是你应该程序运行一段代码是遇到一个类就要其父类进行加载,一次上去都不能加载的话,就自己进行加载!下次再讲一些关于JVM和垃圾回收机制方面的东西吧!
?