java虚拟机的类加载器

时间:2022-12-27 12:53:02

一、类的加载可以简单分成两种方式,静态加载和动态加载。

  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堆中,虽有可以打印出来。

三、类加载双亲委派机制