java虚拟机的类加载器
一、类的加载可以简单分成两种方式,静态加载和动态加载。
1、静态加载,就是new等方式使用到一个类的实例时,程序在运行到该处时,会把该类的.class文件加载到jvm里。
2、动态加载,通过Class.forName()或类加载器的方式,通过类的全名限定把.class文件加载到jvm里。
forName()方式:
@Test public void testClass() throws InstantiationException, IllegalAccessException, ClassNotFoundException { Emp emp = (Emp) Class.forName("entity.Emp").newInstance(); System.out.println(emp); }
结果:
Emp [name=null, age=0, address=null, date=null]
类加载的方式:需要一个ClassLoader的实例,运行它的loadClass()方法,一般使用本类的类加载,或自定义类的加载器。
@Test public void testClassLoader() throws InstantiationException, IllegalAccessException, ClassNotFoundException { //本类的类加载器使用方式 ClassLoader thisLoader = this.getClass().getClassLoader(); Emp empOne = (Emp) thisLoader.loadClass("entity.Emp").newInstance(); System.out.println(empOne); //其他类的使用 ClassLoader classLoader = Emp.class.getClassLoader(); Emp empTwo = (Emp) classLoader.loadClass("entity.Emp").newInstance(); System.out.println(empTwo); }
结果:
Emp [name=null, age=0, address=null, date=null] Emp [name=null, age=0, address=null, date=null]
二、类加载的机制
类加载器的层次关系:
*仅仅是层次关系,非继承关系
*它并不是一个强制性的约束模型,而是Java设计者推荐给开发者的一种类加载器实现方式
启动类加载器 Bootstrap ClassLoader
↑
扩展类加载器 Extension ClassLoader
↑
应用程序类加载器 Application ClassLoader
↑
自定义类加载器 Custom ClassLoader
1、启动类加载器Bootstrap ClassLoader
这是一个嵌在JVM内核中的加载器。它负责加载的是JAVA_HOME/lib下的类库,系统类加载器无法被Java程序直接应用
2、扩展类加载器Extension ClassLoader
这个类加载器由sun.misc.Launcher$ExtClassLoader实现,它负责用于加载JAVA_HOME/lib/ext目录中的,或者被java.ext.dirs系统变量指定所指定的路径中所有类库,开发者可以直接使用扩展类加载器。java.ext.dirs系统变量所指定的路径的可以通过程序来查看
@Test public void testdirs() { System.out.println(System.getProperty("java.ext.dirs")); }
结果:
D:\java\jdk1.8.0_91\jre\lib\ext;C:\Windows\Sun\Java\lib\ext
3、应用程序类加载器Application ClassLoader
这个类加载器由sun.misc.Launcher$AppClassLoader实现。这个类也一般被称为系统类加载器,会加载java.class.path下的类文件。
这个目录包括了项目中类的.class问价,即编译后项目的bin目录,和项目引用的第三发jar包或通过maven引用的jar包等。
@Test public void testdirs() { System.out.println(System.getProperty("java.class.path")); }
结果:
D:\git\basicCode\bin;C:\Users\lizihao\.p2\pool\plugins\org.junit_4.12.0.v201504281640\junit.jar;C:\Users\lizihao\.p2\pool\plugins\org.hamcrest.core_1.3.0.v20180420-1519.jar;D:\git\basicCode\jar\commons-io-2.5.jar;D:\git\basicCode\jar\dom4j-1.6.1.jar;D:\git\basicCode\jar\sqljdbc42.jar;D:\git\basicCode\jar\ojdbc6.jar;D:\git\basicCode\jar\json-20160810.jar;D:\git\basicCode\jar\itextpdfjar\barcodes-7.1.4.jar;D:\git\basicCode\jar\itextpdfjar\font-asian-7.1.4.jar;D:\git\basicCode\jar\itextpdfjar\forms-7.1.4.jar;D:\git\basicCode\jar\itextpdfjar\hyph-7.1.4.jar;D:\git\basicCode\jar\itextpdfjar\io-7.1.4.jar;D:\git\basicCode\jar\itextpdfjar\kernel-7.1.4.jar;D:\git\basicCode\jar\itextpdfjar\layout-7.1.4.jar;D:\git\basicCode\jar\itextpdfjar\pdfa-7.1.4.jar;D:\git\basicCode\jar\itextpdfjar\sign-7.1.4.jar;D:\git\basicCode\jar\itextpdfjar\styled-xml-parser-7.1.4.jar;D:\git\basicCode\jar\itextpdfjar\svg-7.1.4.jar;D:\git\basicCode\jar\itextpdfjar\slf4j-api-1.7.13.jar;D:\git\basicCode\jar\mysql-connector-java-5.1.47.jar;D:\java\eclipse\eclipse\configuration\org.eclipse.osgi\417\0\.cp;D:\java\eclipse\eclipse\configuration\org.eclipse.osgi\416\0\.cp
类加载器:
@Test public void testdirs() { System.out.println(this.getClass().getClassLoader()); System.out.println(this.getClass().getClassLoader().getParent()); System.out.println(this.getClass().getClassLoader().getParent().getParent()); }
结果:
sun.misc.Launcher$AppClassLoader@60e53b93 sun.misc.Launcher$ExtClassLoader@27c170f0 null
从结果可以看出来,我自定义的测试类的使用的是应用程序类加载器Application ClassLoader,它的父类加载器(非继承意义上的父类)是扩展类加载器Extension ClassLoader,而在往上的启动类加载器Bootstrap ClassLoader是null,因为jvm的一部分,是c/c++写的,所以没有保存在java堆中,其他加载器都是java实现的,类型信息class实例保存在java堆中,虽有可以打印出来。
三、类加载双亲委派机制