首页 > 学院 > 开发设计 > 正文

类加载机制

2019-11-06 07:29:52
字体:
来源:转载
供稿:网友

一类的加载连接和初始化1JVM的启动和终止 2类的加载 3类的连接4类的初始化1目的2方式3初始化步骤6初始化时机当java程序首次通过下面6种方式来使用某个类或接口时系统就会初始化该类或接口二类加载器1类加载器简介2加载器层次结构1Bootstrap根引导或原始类加载器2Extension Classloader扩展类加载器3 System ClassLoader系统应用类加载器3类加载机制1三种类加载机制2父子关系3实现类4加载步骤5创建并使用自定义的类加载器classLoader的一些方法

一、类的加载、连接和初始化

1、JVM的启动和终止

当调用Java命令调用某个Java程序时,该命令将会启动一个JVM同一个JVM的所有线程、所有变量都处于同一个进程中,他们都是使用该JVM进程的内存区。当系统出现一下集中情况时,JVM进程将被终止:
程序运行到最后正常结束程序运行到使用System.exit()或Runtime.getRuntime().exit()代码处结束程序程序执行过程中遇到未捕获的异常或错误而结束

2、类的加载

当程序主动使用某个类时,如果该类还未加载到内存中,则系统会通过加载、连接和初始化3个步骤对该类进行初始化类加载指的是将类的class文件读入内存,并为止创建一个java.lang.Class对象类的加载由类加载器完成,类加载器通常由JVM提供称为系统类加载器开发者可以通过继承ClassLoadder基类来创建自己的类加载器通过使用不同的类加载器,可以从不同的来源加载类的二进制数据,通常有如下几种来源

从本地文件系统加载class文件,这是前面绝大部分示例程序的类加载方式从JAR包加载class文件,这种方式也是很常见的,前面介绍JDBC编程时用到的数据库驱动类就放在JAR文件中,JVM可以从JAR文件中直接加载该class文件通过网络加载class文件把一个Java源文件动态编译,并执行加载 Java虚拟机允许系统预先加载某些类,也可以等到首次使用时才加入该类

3、类的连接

当类被加载之后,系统为之生成一个对应的class对象,接着会进入连接阶段

连接阶段负责把类的二进制数据合并到JRE中

类的连接又可分为如下三个阶段

(1)验证:验证阶段用于检验被加载的类是否有正确的内部结构(2)准备:类准备阶段则负责为类的静态Field分配内存,并设置默认初始值(3)解析:将类的二进制数据中的符号引用替换成直接引用

4、类的初始化

4.1目的

主要是对静态Field进行初始化

4.2方式

声明静态Field时指定初始值使用静态初始化块指定初始值 JVM会按这些语句在程序中的执行顺序依次执行他们

4.3初始化步骤

(1)假如这个类还没有加载和连接,则程序先加载并连接该类(2)假如该类的直接父类还没有被初始化,则先初始化其直接父类(3)假如类中有初始化语句,则系统依次执行这些初始化语句

4.6初始化时机

当Java程序首次通过下面6种方式来使用某个类或接口时,系统就会初始化该类或接口

创建类的实例。为某个类创建实例的方式包括:使用new操作符来创建实例,通过反射来创建实例,通过反序列化的方式来创建实例调用某个类的静态方法访问某个类或接口的静态Field或为该静态Field赋值使用反射方式来强制创建某个类或接口对应的java.lang.Class对象。例如代码:Class.forName(“Person”),如果系统还未初始化Person类,则这行代码将会导致该Person类被初始化,并返回Person类对应的java.lang.Class对象。初始化某个类的子类。当初始化某个类的子类时,该子类的所有父类都会被初始化。直接使用java.exe命令来运行某个主类。当运行某个主类时,程序会先初始化该主类 注意当某个静态Field使用了final修饰,而且它的值在编译时就可以确定下来,那么程序其他地方使用该静态Field时,相当于使用常量,静态Field所在的类也不会初始化当使用ClassLoader类的loadClass()方法来加载某个类时,该方法只是加载该类,并不会执行该类的初始化

二、类加载器

1、类加载器简介

类加载器负责加载所有的类,系统为所有被载入内存中的类生成一个java.lang.Class实例 一旦一个类被载入JVM中,同一个类就不会被再次载入了 在JVM中,一个类用其全限定名和其类加载器作为其唯一标识(类名,包名,类加载器实例),如(Person,pg,k1)

2、加载器层次结构

2.1、Bootstrap:根(引导或原始)类加载器

负责加载Java的和核心类

file:/D:/Java/jdk1.7.0/jre/lib/resources.jarfile:/D:/Java/jdk1.7.0/jre/lib/rt.jarfile:/D:/Java/jdk1.7.0/jre/lib/sunrsasign.jarfile:/D:/Java/jdk1.7.0/jre/lib/jsse.jarfile:/D:/Java/jdk1.7.0/jre/lib/jce.jarfile:/D:/Java/jdk1.7.0/jre/lib/charsets.jarfile:/D:/Java/jdk1.7.0/jre/lib/classes.jar

指定加载附加类

java.exe -Xbootclasspathjava.exe -D(sun.boot.class.path)

根类加载器不是ClassLoader的子类 获取根类加载器所加载的全部URL数组

URL[] urls=aun.misc.Launcher.getBootstrapClassPath().getURLs();for(int i=0;i<urls.length;i++){ System.out.PRintln(urls[i].toExternalForm());}

2.2Extension Classloader:扩展类加载器

负责加载JRE的扩展目录

./jre/ib/extjava.ext.dirs

2.3 System ClassLoader:系统(应用)类加载器

负责加载以下命令或属性指定的

java -classpathjava.class.pathCLASSPATH 获取系统类加载器ClassLoader.getSystemLoader

3、类加载机制

3.1、三种类加载机制

全盘负责 所谓全盘负责,就是当一个类加载器负责加载某个Class时,该Class所依赖的和引用的其他Class也将由该类加载器负责载入,除非显示使用另外一个类加载器来载入。父类委托 所谓父类委托,则是先让parent(父)类加载器试图加载该Class,只有在父类加载器无法加载该类时才尝试从自己的类路径中加载该类。缓存机制 缓存机制将会保证所有加载过的Class都会被缓存,当程序中需要使用某个Class时,类加载器先从缓存区中搜寻该class,只有当缓存区中不存在该class对象时,系统才会读取该类对应的二进制数据,并将其转换成class对象,存入缓存区中。这就是为什么修改了class后,必须重新启动JVM,程序所做的修改才会生效的原因。

3.2父子关系

Created with Raphaël 2.1.0用户类加载器系统类加载器扩展类加载器根类加载器

3.3实现类

系统类加载器是AppClassLoader的实例,扩展类加载器是ExtClassLoader的实例。实际上,这两个类都是URLClassLoader类的实例。 JVM的根类加载器并不是Java实现的,而且由于程序通常无需访问访问根类加载器,因此访问扩展类加载器的父类加载器时返回null。

3.4加载步骤

Created with Raphaël 2.1.0开始检查是否载入过返回对应的java.lang.Class对象父类加载器是否存在请求使用父类加载器父类加载器载入Class是否成功当前类加载器尝试寻找Class文件(从与此ClassLoader相关的类路径中寻找)当前类加载器是否找到class文件从文件中载入class请求使用根类加载器根类加载器载入Class是否成功yesnoyesnoyesnoyesyes

3.5创建并使用自定义的类加载器

classLoader的一些方法
loadClass(String name,boolean resolve):该方法为ClassLoader的入口点,根据指定的二进制名称来加载类,系统就是调用ClassLoader的该方法来获取指定类对应的Class对象。findClass(String name):根据二进制名称来查找类。findSystemClass(String name):从本地文件系统装入文件,它在本地文件系统中寻找类文件,如果存在,就使用defineClass()方法将原始字节转换成Class对象,以将该文件转换成类。static getSystemClassLoader():这是一个静态方法,用于返回系统类加载器。getParent():获取该类加载器的父类加载器。resolveClass(Class
上一篇:友元类

下一篇:BZOJ 3991 set维护dfs序

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表