作用:
三个阶段:
1、加载阶段
这个阶段主要是读取字节码文件。2、链接阶段
验证:查看 class 的二进制文件,能查看到是以 CA FE BA EE开头,说明这是一个符合要求的字节码文件。可以防止恶意文件危害虚拟机的安全。
准备:在这个阶段会为类变量分配默认的值。如:int 类型为0,char 类型为\u0000,float 类型为0.0f,boolean 为false,引用类型为null。这里不包含 final 修饰的 static ,这些数据会直接初始化。
解析:如上图。
3、初始化
- 初始化阶段,按照顺序来赋值。
为什么把 number 定义在下面,但是可以在上面赋值呢?因为我们前面在链接阶段说过,变量首先会初始化该类型的默认值即 0。所以可以直接赋值,但是不能前向引用。 - 父类在子类之前加载。
上面的例子结果为2。 - 虚拟机必须保证一个类的()方法在多线程下被同步加锁。
两种类加载器
1、引导类加载器 BootstrapClassLoader,由 C++ 语言编写,在程序中获取该类加载器得到的是一个null值。
该加载器加载虚拟机核心类库,如以 java、javax、sun 开头的包下的类。
2、自定义加载器,由java编写,常见的是扩展类加载器 ExtensionClassLoader、系统类加载器或叫应用类加载器 AppClassLoader(SystemClassLoader)
其中 ExtensionClassLoader 由 BootstrapClassLoader 加载, AppClassLoader 由 ExtensionClassLoader 加载,常称引导类加载器是扩展类加载器的父类,而扩展类加载器是系统类加载器的父类。
其中扩展类加载器加载目录 jre/lib/ext 下的类库,系统类加载器负责加载 classpath 或者 java.class.path 指定路径下的类库。
双亲委派机制:
某个特定的类加载器在接到加载类的请求时,首先将加载任务委托给父类加载器,依次递归,如果父类加载器可以完成类加载任务,就成功返回;只有父类加载器无法完成此加载任务时,才自己去加载。
例:
我们在项目下创建一个 java.lang 的包,然后在包下创建一个 String 类。
另外在这个包外创建主方法入口
如果创建的这个 String 类是由我们创建的话,那么会打印 " 我是自定义 String 类 ",运行程序,得到下面结果:
原因:由于双亲委派机制的存在,系统类加载器接收到创建 String 类的请求,将请求交给扩展类,扩展类交给引导类。引导类发现 java.lang 这个路径在自己的管理范围内,就把 java 自带 String 类加载,就不把请求向下传递了。反之,则需要向下传递,一直到系统类加载器把需要的类加载。
优点:
1.防止类的重复加载
2.保护程序安全,防止核心 Api 被修改。