类加载详细过程:
加载:
)通过类的全限定名获取该类的二进制字节流
)将二进制流所代表的静态结构转化为方法区的运行时数据结构
)在内存中创建一个代表该类的java.lang.Class
对象,作为方法区中这个类的各种数据的访问入口
验证:
java
语法规范准备:正式为类变量(或者静态成员变量)分配内存并设置初始值,这些变量(不包括实例变量)所使用的内存都在方法区进行分配
解析:虚拟机将常量池中的符号引用替换为直接引用
初始化:执行类构造器
方法的过程
方法是由编译器自动收集类中的所有类变量的赋值动作和静态语句块中语句合并产生的,编译器收集的顺序是由语句在源文件中出现的顺序所决定的。
5种情况会触发初始化:
1)遇到new、getstatic、putstatic、invokestatic
这四条季节吗指令的时候,如果类没有经过初始化,则需要触发类的初始化。场景是:new实例化对象、设置类的静态字段、读取类的静态字段、调用类的静态方法。
2)使用java.lang.reflect
包的方法对类进行反射调用的时候,如果类没有进行过初始化,则需要触发其初始化
3)当初始化一个类的时候,发现其父类还没有进行过初始化,则需要先触发其父类的初始化
4)当虚拟机启动的时候,用户需要指定一个要执行的主类,即包含main方法的类,虚拟机会先初始化这个主类
5)当使用jdk1.7
动态语言支持时,如果一个java.lang.invoke.MethodHandle
实例最后的解析结果是 REF_getstatic
,REF_putstatic
,REF_invokeStatic
的方法句柄,并且这个方法句柄对应的类没有进行初始化,则主要触发其初始化
任意一个类 + 加载它的类加载器 ==》其在 Java 虚拟机中的唯一性;每一个类加载器,都有一个独立的类名称空间。
比较两个类是否“相等”,只有在这两个类是由同一个类加载器加载的前提下才有意义,否则,即使这两个类来源于同一个 Class 文件,被同一个虚拟机加载,只要加载它们的类加载器不同,那么这两个类就必定不相等。
这里的“相等”,包括代表类的 Class 对象的 equals() 方法、
isInstance()
方法的返回结果,也包括使用instanceof
关键字做对象所属关系判定等情况。
\lib
目录中的,并且能被虚拟机识别的(仅按照文件名识别,如 rt.jar
,名字不符合的类库即使放在 lib 目录中也不会被加载)类库加载到虚拟机内存中。\lib\ext
目录中的所有类库,开发者可以直接使用扩展类加载器。ClassLoader
中的 getSystemClassLoader()
方法的返回值,所以一般也称它为“系统类加载器”。它负责加载用户类路径(classpath
)上所指定的类库,开发者可以直接使用这个类加载器,如果应用程序中没有自定义过自己的类加载器,一般情况下这个就是程序中默认的类加载器。双亲委派模型是描述类加载器之间的层次关系。它要求除了顶层的启动类加载器外,其余的类加载器都应当有自己的父类加载器。(父子关系一般不会以继承的关系实现,而是以组合关系来复用父加载器的代码)
java.lang.ClassLoader
中的 loadClass()
方法中实现该过程。)java.lang.Object
这些存放在 rt.jar
中的类,无论使用哪个类加载器加载,最终都会委派给最顶端的启动类加载器加载,从而使得不同加载器加载的 Object 类都是同一个。相反,如果没有使用双亲委派模型,由各个类加载器自行去加载的话,如果用户自己编写了一个称为 java.lang.Object
的类,并放在 classpath
下,那么系统将会出现多个不同的 Object 类,Java 类型体系中最基础的行为也就无法保证。