类->加载->链接->初始化
类加载,最终定义一个类,将字节码转化为Class类的对象
1、类加载器分为两类
用户自定义类加载器---继承ClassLoader类,同时jiJVM会提供一些默认实现
启动类加载器---由JVM的原生的代码生成
最常用的system类加载器 通过ClassLoader的getSystemClassLoader()方法可以获取该类加载器的对象
2、 类加载器的重要特征
层次结构---每个类加载器都由父类结构,可以通过getParent()得到
代理模式---类加载器可以将类加载交给其他类加载器来完成,也可以自己完成。
初始类加载器---启动类的加载过程的加载器
定义类加载器---最终定义类的加载器
当B类被A类导入时,B类由A的定义类加载器启动其加载过程
3、类加载顺序
首先交由父类加载器,找不到就自己来。
servlet规范中推荐相反的策略,即,tomcat为每个应用提供一个独立的类加载器,使用自己优先的策略
IBM WebSphere则允许web应用程序选择类加载器使用的策略
4、类加载器用途
为相同名称的java类创建隔离空间
java类的不同版本在JVM中同时存在
注意:判断两个类是否相同,不仅是根据该类的二进制名称,还需要两个类的类加载器相同,相同的java字节码,被不同类加载器定义后,所得到的java类不同
在两个类的对象之间进行赋值操作,会抛出ClassCastException
类链接
java类的二进制代码合并到JVM 运行状态之中,步骤,验证,准备,解析等。
1、验证
确保java类的二进制表示在结构上是正确的。如果错误抛出java.lang.VerifyError
2、准备
创建java类的静态域,设置默认值,不会执行代码
3、解析
确保父类,实现的接口,方法的形参,返回值的java类可以被正确找到(该过程会加载器其他类)
注意:不同的JVM由不同的解析策略,
1、在链接的时候就递归的把所依赖的形式引用进行解析
2、只在真正用到的时候再进行解析
如果被引用,但没有被用到,可能就不会被解析
类的初始化
类被真正使用到的时候
1、JVM进行初始化操作,执行静态域代码块和初始化静态域(依次执行,单线程中)
2、类初始化之前,他的直接父类也需要被初始化,但是接口的初始化不会引起父接口初始化。
3、发生时间
创建一个类的实例
调用一个类的静态方法
类或接口中声明的静态域赋值
访问类或接口中声明的静态域,并且该域不是常值变量
注意:访问一个类或接口的静态域的时候,只有真正声明的这个类才会被初始化
子类继承父类时,父类特有的域,被第三方通过子类调用,,此时只有父类会被初始化,子类不会被初始化。
创建自定义类加载器
1、应用场景
实现特定的java字节代码查找方式
对字节码进行加密/解码,实现同名类的隔离
2、步骤,继承ClassLoader类,覆写方法
defineClass(),完成字节代码的字节数组到java.lang.Class 转化,不能被覆写
findClassLoader() 根据名字查找已经加载过的类,一个类加载器不会重复加载同一名称的类
findClass() 根据名称查找并加载类-----添加自定义的类加载器逻辑,loadClass方法默认负责调用
loadClass()根据名称加载类----代理模式封装在此,需要修改策略的可以覆写loadClass()方法
resolveClass()链接类
类加载,最终定义一个类,将字节码转化为Class类的对象
1、类加载器分为两类
用户自定义类加载器---继承ClassLoader类,同时jiJVM会提供一些默认实现
启动类加载器---由JVM的原生的代码生成
最常用的system类加载器 通过ClassLoader的getSystemClassLoader()方法可以获取该类加载器的对象
2、 类加载器的重要特征
层次结构---每个类加载器都由父类结构,可以通过getParent()得到
代理模式---类加载器可以将类加载交给其他类加载器来完成,也可以自己完成。
初始类加载器---启动类的加载过程的加载器
定义类加载器---最终定义类的加载器
当B类被A类导入时,B类由A的定义类加载器启动其加载过程
3、类加载顺序
首先交由父类加载器,找不到就自己来。
servlet规范中推荐相反的策略,即,tomcat为每个应用提供一个独立的类加载器,使用自己优先的策略
IBM WebSphere则允许web应用程序选择类加载器使用的策略
4、类加载器用途
为相同名称的java类创建隔离空间
java类的不同版本在JVM中同时存在
注意:判断两个类是否相同,不仅是根据该类的二进制名称,还需要两个类的类加载器相同,相同的java字节码,被不同类加载器定义后,所得到的java类不同
在两个类的对象之间进行赋值操作,会抛出ClassCastException
类链接
java类的二进制代码合并到JVM 运行状态之中,步骤,验证,准备,解析等。
1、验证
确保java类的二进制表示在结构上是正确的。如果错误抛出java.lang.VerifyError
2、准备
创建java类的静态域,设置默认值,不会执行代码
3、解析
确保父类,实现的接口,方法的形参,返回值的java类可以被正确找到(该过程会加载器其他类)
注意:不同的JVM由不同的解析策略,
1、在链接的时候就递归的把所依赖的形式引用进行解析
2、只在真正用到的时候再进行解析
如果被引用,但没有被用到,可能就不会被解析
类的初始化
类被真正使用到的时候
1、JVM进行初始化操作,执行静态域代码块和初始化静态域(依次执行,单线程中)
2、类初始化之前,他的直接父类也需要被初始化,但是接口的初始化不会引起父接口初始化。
3、发生时间
创建一个类的实例
调用一个类的静态方法
类或接口中声明的静态域赋值
访问类或接口中声明的静态域,并且该域不是常值变量
注意:访问一个类或接口的静态域的时候,只有真正声明的这个类才会被初始化
子类继承父类时,父类特有的域,被第三方通过子类调用,,此时只有父类会被初始化,子类不会被初始化。
创建自定义类加载器
1、应用场景
实现特定的java字节代码查找方式
对字节码进行加密/解码,实现同名类的隔离
2、步骤,继承ClassLoader类,覆写方法
defineClass(),完成字节代码的字节数组到java.lang.Class 转化,不能被覆写
findClassLoader() 根据名字查找已经加载过的类,一个类加载器不会重复加载同一名称的类
findClass() 根据名称查找并加载类-----添加自定义的类加载器逻辑,loadClass方法默认负责调用
loadClass()根据名称加载类----代理模式封装在此,需要修改策略的可以覆写loadClass()方法
resolveClass()链接类
参考infoQ《java深度历险》