加载过程可以分为3大阶段:加载 - 链接(验证 -准备 - 解析) - 初始化,如下图:
这里的加载可以从字面意思理解,主要作用是将外部的 .class 文件转换为二进制数据并加载到JVM的方法区内 , 这里的外部可以指:jar、war、网络中等等
校验 class 文件的格式对否满足JVM规范,不符合规范的将抛出 java.lang.VerifyError 错误
为类变量分配内存,并将其初始化为默认值。此时,实例对象还没有分配内存,所以这些动作是在方法区上进行的。
类变量有两次赋初始值的过程,一次在准备阶段,赋予初始值(也可以是指定值);另外一次在初始化阶段,赋予程序员定义的值。因此,即使程序员没有为类变量赋值也没有关系,它仍然有一个默认的初始值。但局部变量就不一样了,如果没有给它赋初始值,是不能使用的。
将符号引用替换为直接引用的过程,符号引用是一种定义,可以是任何字面上的含义,而直接引用就是直接指向目标的指针、相对偏移量 。 这个阶段大体可以分为:
我们经常发生的异常,就与这个阶段有关。
java.lang.NoSuchFieldError
根据继承关系从下往上,找不到相关字段时的报错。java.lang.IllegalAccessError
字段或者方法,访问权限不具备时的错误。java.lang.NoSuchMethodError
找不到相关方法时的错误。解析过程保证了相互引用的完整性,把继承与组合推进到运行时
进行成员变量的初始化工作
类加载器负责类的加载工作,安全、校验等工作都由它来负责。
它的作用是加载核心类库,也就是 rt.jar、resources.jar、charsets.jar 等。当然这些 jar 包的路径是可以指定的,-Xbootclasspath 参数可以完成指定操作。这个加载器是 C++ 编写的,随着 JVM 启动
扩展类加载器,主要用于加载 lib/ext 目录下的 jar 包和 .class 文件。同样的,通过系统变量 java.ext.dirs 可以指定这个目录。这个加载器是个 Java 类,继承自 URLClassLoader
我们写的 Java 类的默认加载器,有时候也叫作 System ClassLoader。一般用来加载 classpath 下的其他所有 jar 包和 .class 文件,我们写的代码,会首先尝试使用这个类加载器进行加载
自定义加载器,支持一些个性化的扩展功能
在加载一个类的时候,无论子类是否有能力加载,都要先依托父类加载,如果父类没有能力加载那么子类才会加载,这种机制称为双亲委派机制,个人理解双亲就是指:bootstrap、extention classloader。好处是:保证一个类只会被加载一次、并且安全,想象一下如果Object存在于多个,程序会是什么样子。
重写loadclass
方法即可打破双亲委派机制
Tomcat在加载webapp的时候为了保证多个app的隔离性,加载时是由子类优先加载的,加载不到才会交给父类加载
ServiceLoader.java 是属于bootstrap classloader 加载的类 , 如果按双清委派模型的话是不可能加载到三方jar中的类的。但是JDK玩了一个小技巧:把加载三方jar的类加载器设置为Thread.currentThread().getContextClassLoader()
d , 我们知道线程上下文类加载器默认为application classloader。
原文:https://www.cnblogs.com/lihuamaoa/p/13291417.html