一、什么是类的加载机制
虚拟机把描述类的数据从Class文件加载到内存,并对数据进行校验、转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型,这就是虚拟机的类加载机制。
类的加载指的是将类从“.java”代码文件编译成的“.class”字节码文件中的二进制数据读入到内存中,将其放在运行时数据区的方法区内,然后在堆区(HotSpot虚拟机在方法区中)创建一个java.lang.Class
对象,用来封装类在方法区内的数据结构。类的加载的最终产品是位于堆区中的Class
对象,Class
对象封装了类在方法区内的数据结构,并且向Java程序员提供了访问方法区内的数据结构的接口。
一般情况在你的代码中用到这个类的时候,才会加载这个类,但是类加载器并不需要等到某个类被“首次主动使用”时再加载它,JVM规范允许类加载器在预料某个类将要被使用时就预先加载它,如果在预先加载的过程中遇到了.class文件缺失或存在错误,类加载器必须在程序首次主动使用该类时才报告错误(LinkageError错误)如果这个类一直没有被程序主动使用,那么类加载器就不会报告错误。
二、类的生命周期
类从被加载到虚拟机内存中开始,到卸载出内存为止,它的整个生命周期包括:加载(Loading)、验证(Verification)、准备(Preparation)、解析(Resolution)、初始化(Initialization)、使用(Using)和卸载(Unloading)7个阶段。其中验证、准备、解析三个阶段统称为连接(Linking),这7个阶段的发生顺序如图:
在类的生命周期图中,加载、验证、准备、初始化和卸载这5个阶段的顺序是确定的,类的加载过程必须按照这种顺序按部就班的开始,而解析阶段则不一定:它在某些情况下可以在初始化阶段之后再开始,这是为了支持Java语言的运行时绑定(动态绑定或者晚期绑定)。
三、类加载器
1.JVM类加载机制
1>全盘负责,当一个类加载器负责加载某个Class时,该Class所依赖的和引用的其他Class也将由该类加载器负责载入,除非显示使用另外一个类加载器来载入
2>父类委托,先让父类加载器试图加载该类,只有在父类加载器无法加载该类时才尝试从自己的类路径中加载该类
3>缓存机制,缓存机制将会保证所有加载过的Class都会被缓存,当程序中需要使用某个Class时,类加载器先从缓存区寻找该Class,只有缓存区不存在,系统才会读取该类对应的二进制数据,并将其转换成Class对象,存入缓存区。这就是为什么修改了Class后,必须重启JVM,程序的修改才会生效。
2.类加载有三种方式
1>命令行启动应用时候由JVM初始化加载
2>通过Class.forName()方法动态加载
3>通过ClassLoader.loadClass()方法动态加载
3.Class.forName()和ClassLoader.loadClass()区别
1>Class.forName()
:将类的.class文件加载到jvm中之外,还会对类进行初始化,执行类中的static块;
2>ClassLoader.loadClass()
:只干一件事情,就是将.class文件加载到jvm中,不会执行static中的内容,只有在newInstance才会去执行static块。
3>Class.forName(name,initialize,loader)
带参函数也可控制是否加载static块。并且只有调用了newInstance()方法才用调用构造函数,创建类的对象 。
4.基于双亲委派的类加载器
从Java虚拟机角度,只存在两种类加载器:(1)启动类加载器(Bootstrap ClassLoader),它是由C++实现的,是虚拟机自身的一部分。(2)所有其他的类加载器,这些类加载器都是用Java实现的,独立于虚拟机外部,并且全部继承自抽象类java.lang.ClassLoader。绝大多数java程序会用到以下三种系统提供的类加载器:
1>启动类加载器(Bootstrap ClassLoader):这个类加载器负责将存放在<JAVA_HOME>\lib目录中的或者被-Xbootrclasspath参数所指定的路径中的,并且是虚拟机识别的类库(如rt.jar,所有的java.开头的类均被 BootstrapClassLoader
加载)加载到虚拟机内存中。启动类加载器无法被Java程序直接引用,用户在编写自定义类加载器时,如果需要把加载请求委派给启动类加载器,那么直接使用null替代即可。
2>扩展类加载器(Extension ClassLoader):这个加载器由sun.misc.Launcher$ExtClassLoader实现,负责加载<JAVA_HOME>\lib\ext目录中的,或者被java.ext.dirs系统变量所指定的路径中的所有类库(如javax.开头的类),开发者可以直接使用扩展类加载器。
3>应用程序类加载器(Application ClassLoader):这个加载器由sun.misc.Launcher$AppClassLoader实现,这个类加载器是ClassLoader中的getSystemClassLoader方法的返回值,所以一般也称为系统类加载器。负责加载用户类路径(ClassPath)上的所指定的类库,开发者可以直接使用,如果应用程序中没有自定义过类加载器,一般情况下,应用程序类加载器就是默认的类加载器。
上图展示的层次关系,称为类加载器的双亲委派模型(Parents Delegation Model)。双亲委派模型要求除了顶层的启动类加载器外,其余的类加载器都有自己的父类加载器。这里的类加载器之间的父子关系一般不会以继承的关系存在,而是都使用组合关系来复用父类加载器的代码。
双亲委派模型的工作过程是:
如果一个类加载器收到了类加载的请求,它首先不会自己去尝试加载这个类,而是把这个请求委派给父类加载器去完成,每一个层次的类加载器都是如此,因此所有的类加载请求最终都应该传送到顶层的启动类加载器中,只有当父类加载器反馈自己无法完成这个类加载请求时(它的搜索范围内没有找到所需的类),子类加载器才会尝试自己去加载。
双亲委派模型对保证Java程序的稳定运作很重要,使用双亲委派模型来组织类加载器之间的关系,一个显而易见的好处是Java类随着它的类加载器一起具备了一种带有优先级的层次关系。
例如类java.lang.Object,它存放在rt.jar中,无论哪个类加载器要加载这个类,最终都是委派给了模型最顶端的启动类加载器进行加载,因此Object类在程序的各种类加载器环境中都是同一个类。
相反,如果没有使用双亲委派模型,由各个类加载器自行加载的话,如果用户自己编写了一个java.lang.Object类,并放到程序的ClassPath中,那么系统中将出现多个不同的Object类,Java体系中最基础的行为也就无法保证,应用程序将变得一片混乱。
package com.neo.classloader;
public class ClassLoaderTest{
public static void main(String[] args){
ClassLoader loader = Thread.currentThread().getContextClassLoader();
System.out.println(loader);
System.out.println(loader.getParent());
System.out.println(loader.getParent().getParent());
}
}
运行结果:
sun.misc.Launcher$AppClassLoader@64fef26a
sun.misc.Launcher$ExtClassLoader@1ddd40f3
null
从上面的结果可以看出,并没有获取到 ExtClassLoader
的父Loader,原因是 BootstrapLoader
(引导类加载器)是用C语言实现的,找不到一个确定的返回父Loader的方式,于是就返回null。
双亲委派模型意义:
1>系统类防止内存中出现多份同样的字节码
2>保证Java程序安全稳定运行
rt.jar包的介绍:
各类加载器加载信息:
package com.tourist.semantic.similarity;
import java.net.URL;
import java.net.URLClassLoader;
public class Test {
public static void main(String[] args) {
System.out.println("BootstrapClassLoader 的加载路径: ");
URL[] urls = sun.misc.Launcher.getBootstrapClassPath().getURLs();
for(URL url : urls)
System.out.println(url);
System.out.println("----------------------------");
//取得扩展类加载器
URLClassLoader extClassLoader = (URLClassLoader)ClassLoader.getSystemClassLoader().getParent();
System.out.println(extClassLoader);
System.out.println("扩展类加载器的加载路径: ");
urls = extClassLoader.getURLs();
for(URL url : urls)
System.out.println(url);
System.out.println("----------------------------");
//取得应用(系统)类加载器
URLClassLoader appClassLoader = (URLClassLoader)ClassLoader.getSystemClassLoader();
System.out.println(appClassLoader);
System.out.println("应用(系统)类加载器的加载路径: ");
urls = appClassLoader.getURLs();
for(URL url : urls)
System.out.println(url);
System.out.println("----------------------------");
}
}
BootstrapClassLoader 的加载路径:
file:/D:/java/jdk1.8.0_162/jre/lib/resources.jar
file:/D:/java/jdk1.8.0_162/jre/lib/rt.jar
file:/D:/java/jdk1.8.0_162/jre/lib/sunrsasign.jar
file:/D:/java/jdk1.8.0_162/jre/lib/jsse.jar
file:/D:/java/jdk1.8.0_162/jre/lib/jce.jar
file:/D:/java/jdk1.8.0_162/jre/lib/charsets.jar
file:/D:/java/jdk1.8.0_162/jre/lib/jfr.jar
file:/D:/java/jdk1.8.0_162/jre/classes
----------------------------
sun.misc.Launcher$ExtClassLoader@1ab7765
扩展类加载器的加载路径:
file:/D:/java/jdk1.8.0_162/jre/lib/ext/access-bridge-32.jar
file:/D:/java/jdk1.8.0_162/jre/lib/ext/cldrdata.jar
file:/D:/java/jdk1.8.0_162/jre/lib/ext/dnsns.jar
file:/D:/java/jdk1.8.0_162/jre/lib/ext/jaccess.jar
file:/D:/java/jdk1.8.0_162/jre/lib/ext/jfxrt.jar
file:/D:/java/jdk1.8.0_162/jre/lib/ext/localedata.jar
file:/D:/java/jdk1.8.0_162/jre/lib/ext/nashorn.jar
file:/D:/java/jdk1.8.0_162/jre/lib/ext/sunec.jar
file:/D:/java/jdk1.8.0_162/jre/lib/ext/sunjce_provider.jar
file:/D:/java/jdk1.8.0_162/jre/lib/ext/sunmscapi.jar
file:/D:/java/jdk1.8.0_162/jre/lib/ext/sunpkcs11.jar
file:/D:/java/jdk1.8.0_162/jre/lib/ext/zipfs.jar
----------------------------
sun.misc.Launcher$AppClassLoader@b4aac2
应用(系统)类加载器的加载路径:
file:/D:/java/jdk1.8.0_162/jre/lib/charsets.jar
file:/D:/java/jdk1.8.0_162/jre/lib/deploy.jar
file:/D:/java/jdk1.8.0_162/jre/lib/ext/access-bridge-32.jar
file:/D:/java/jdk1.8.0_162/jre/lib/ext/cldrdata.jar
file:/D:/java/jdk1.8.0_162/jre/lib/ext/dnsns.jar
file:/D:/java/jdk1.8.0_162/jre/lib/ext/jaccess.jar
file:/D:/java/jdk1.8.0_162/jre/lib/ext/jfxrt.jar
file:/D:/java/jdk1.8.0_162/jre/lib/ext/localedata.jar
file:/D:/java/jdk1.8.0_162/jre/lib/ext/nashorn.jar
file:/D:/java/jdk1.8.0_162/jre/lib/ext/sunec.jar
file:/D:/java/jdk1.8.0_162/jre/lib/ext/sunjce_provider.jar
file:/D:/java/jdk1.8.0_162/jre/lib/ext/sunmscapi.jar
file:/D:/java/jdk1.8.0_162/jre/lib/ext/sunpkcs11.jar
file:/D:/java/jdk1.8.0_162/jre/lib/ext/zipfs.jar
file:/D:/java/jdk1.8.0_162/jre/lib/javaws.jar
file:/D:/java/jdk1.8.0_162/jre/lib/jce.jar
file:/D:/java/jdk1.8.0_162/jre/lib/jfr.jar
file:/D:/java/jdk1.8.0_162/jre/lib/jfxswt.jar
file:/D:/java/jdk1.8.0_162/jre/lib/jsse.jar
file:/D:/java/jdk1.8.0_162/jre/lib/management-agent.jar
file:/D:/java/jdk1.8.0_162/jre/lib/plugin.jar
file:/D:/java/jdk1.8.0_162/jre/lib/resources.jar
file:/D:/java/jdk1.8.0_162/jre/lib/rt.jar
file:/E:/workspaces/TouristTest/target/classes/
file:/D:/mavenLocation/ch/qos/logback/logback-classic/1.1.2/logback-classic-1.1.2.jar
file:/D:/mavenLocation/ch/qos/logback/logback-core/1.1.2/logback-core-1.1.2.jar
file:/D:/mavenLocation/ch/qos/logback/logback-access/1.1.2/logback-access-1.1.2.jar
file:/D:/mavenLocation/org/slf4j/slf4j-api/1.7.7/slf4j-api-1.7.7.jar
file:/D:/mavenLocation/com/hankcs/hanlp/portable-1.5.3/hanlp-portable-1.5.3.jar
file:/D:/mavenLocation/com/hankcs/nlp/hanlp-lucene-plugin/1.1.2/hanlp-lucene-plugin-1.1.2.jar
file:/D:/mavenLocation/org/apache/lucene/lucene-core/5.1.0/lucene-core-5.1.0.jar
file:/D:/mavenLocation/org/apache/lucene/lucene-queryparser/5.1.0/lucene-queryparser-5.1.0.jar
file:/D:/mavenLocation/org/apache/lucene/lucene-queries/5.1.0/lucene-queries-5.1.0.jar
file:/D:/mavenLocation/org/apache/lucene/lucene-sandbox/5.1.0/lucene-sandbox-5.1.0.jar
file:/D:/mavenLocation/org/apache/lucene/lucene-analyzers-common/5.1.0/lucene-analyzers-common-5.1.0.jar
file:/D:/mavenLocation/org/mockito/mockito-all/1.9.5/mockito-all-1.9.5.jar
file:/D:/mavenLocation/org/hamcrest/hamcrest-all/1.3/hamcrest-all-1.3.jar
file:/D:/mavenLocation/args4j/args4j/2.0.16/args4j-2.0.16.jar
file:/D:/mavenLocation/com/google/guava/guava/13.0.1/guava-13.0.1.jar
file:/D:/mavenLocation/org/apache/commons/commons-lang3/3.3.1/commons-lang3-3.3.1.jar
file:/D:/mavenLocation/com/google/collections/google-collections/1.0/google-collections-1.0.jar
file:/D:/mavenLocation/org/apache/jena/jena-tdb/3.1.0/jena-tdb-3.1.0.jar
file:/D:/mavenLocation/org/apache/jena/jena-arq/3.1.0/jena-arq-3.1.0.jar
file:/D:/mavenLocation/org/apache/jena/jena-core/3.1.0/jena-core-3.1.0.jar
file:/D:/mavenLocation/org/apache/jena/jena-iri/3.1.0/jena-iri-3.1.0.jar
file:/D:/mavenLocation/commons-cli/commons-cli/1.3/commons-cli-1.3.jar
file:/D:/mavenLocation/org/apache/jena/jena-base/3.1.0/jena-base-3.1.0.jar
file:/D:/mavenLocation/com/github/andrewoma/dexx/collection/0.6/collection-0.6.jar
file:/D:/mavenLocation/org/apache/jena/jena-shaded-guava/3.1.0/jena-shaded-guava-3.1.0.jar
file:/D:/mavenLocation/org/apache/httpcomponents/httpclient/4.2.6/httpclient-4.2.6.jar
file:/D:/mavenLocation/org/apache/httpcomponents/httpcore/4.2.5/httpcore-4.2.5.jar
file:/D:/mavenLocation/com/github/jsonld-java/jsonld-java/0.7.0/jsonld-java-0.7.0.jar
file:/D:/mavenLocation/com/fasterxml/jackson/core/jackson-core/2.3.3/jackson-core-2.3.3.jar
file:/D:/mavenLocation/com/fasterxml/jackson/core/jackson-databind/2.3.3/jackson-databind-2.3.3.jar
file:/D:/mavenLocation/com/fasterxml/jackson/core/jackson-annotations/2.3.0/jackson-annotations-2.3.0.jar
file:/D:/mavenLocation/commons-io/commons-io/2.4/commons-io-2.4.jar
file:/D:/mavenLocation/org/apache/httpcomponents/httpclient-cache/4.2.6/httpclient-cache-4.2.6.jar
file:/D:/mavenLocation/org/apache/thrift/libthrift/0.9.2/libthrift-0.9.2.jar
file:/D:/mavenLocation/org/slf4j/jcl-over-slf4j/1.7.20/jcl-over-slf4j-1.7.20.jar
file:/D:/mavenLocation/org/apache/commons/commons-csv/1.0/commons-csv-1.0.jar
file:/D:/mavenLocation/net/java/dev/jna/jna/4.0.0/jna-4.0.0.jar
file:/D:/mavenLocation/log4j/log4j/1.2.17/log4j-1.2.17.jar
file:/D:/mavenLocation/com/hp/hpl/jena/jena/2.6.4/jena-2.6.4.jar
file:/D:/mavenLocation/com/hp/hpl/jena/iri/0.8/iri-0.8.jar
file:/D:/mavenLocation/com/ibm/icu/icu4j/3.4.4/icu4j-3.4.4.jar
file:/D:/mavenLocation/xerces/xercesImpl/2.7.1/xercesImpl-2.7.1.jar
file:/D:/mavenLocation/org/slf4j/slf4j-log4j12/1.5.8/slf4j-log4j12-1.5.8.jar
file:/D:/mavenLocation/mysql/mysql-connector-java/5.1.18/mysql-connector-java-5.1.18.jar
file:/D:/mavenLocation/org/apache/poi/poi-ooxml/3.14/poi-ooxml-3.14.jar
file:/D:/mavenLocation/org/apache/poi/poi/3.14/poi-3.14.jar
file:/D:/mavenLocation/commons-codec/commons-codec/1.10/commons-codec-1.10.jar
file:/D:/mavenLocation/org/apache/poi/poi-ooxml-schemas/3.14/poi-ooxml-schemas-3.14.jar
file:/D:/mavenLocation/org/apache/xmlbeans/xmlbeans/2.6.0/xmlbeans-2.6.0.jar
file:/D:/mavenLocation/stax/stax-api/1.0.1/stax-api-1.0.1.jar
file:/D:/mavenLocation/com/github/virtuald/curvesapi/1.03/curvesapi-1.03.jar
file:/D:/java/ideaIU-2017.3.2.win/lib/idea_rt.jar
来源:CSDN
作者:等待中的小码农
链接:https://blog.csdn.net/zhangting19921121/article/details/104652286