java 复习整理(五 类加载机制与对象初始化)
类加载机制与对象初始化
一 . 类加载机制
类加载机制是指.class文件加载到jvm并形成Class对象的机制。之后应用可对Class对象进行实例化并调用。类加载机制可在运行时动态加载外部的类,还可以达到类隔离的效果。
类从而加载到虚拟机中开始,整个过程分为下图七个阶段,其中验证,准备,解析统称为解析。图中加载,验证,准备,初始化,卸载这5个阶段的顺序是确定的,类的加载过程必须按照这种过程按部就班的开始,而解析则不一定,它在某些情况下可能在初始化之后才开始,这是为了支持java语言的运行时绑定。

1 . 装载: 装载过程负责找到二进制字节码并加载至JVM--即负责查找和导入class文件。
2 . 链接:
(1) 检验:链接过程负责对二进制字节码的格式进行检验,检查class文件数据的正确性
(2) 准备:初始化装载类中的静态变量,给类的静态变量分配存储空间
(3) 解析:解析类中调用的接口,类,将符号引用转为直接引用。3 . 初始化:初始化过程即执行类中的静态初始化代码,构造器代码以及静态属性的初始化。以下四种情况会立即触发初始化
(1) 调用了new,读取或设置一个类的静态字段的时候,或者调用一个类的静态方法的时候。
(2) 反射调用了类中的方法
(3) 子类调用了初始化,如果子类初始化的时候发现父类尚未初始化,则会先出发父类的初始化。
(4) JVM启动过程中指定的初始化类(包含main方法的类)
(5)当使用JDK 1.7的动态语言支持时,如果一个java.lang.invoke.MethodHandle实例最后的解析结果REF_getStatic,REF_putStatic,REF_invokeStatic的方法句柄,并且这个方法句柄对应的类没有初始化,则需要先触发其初始化.
JVM 的类加载通过ClassLoader及其子类来完成,分别是Bootstrap ClassLoader,Extension ClassLoader,App ClassLoader 以及用户自定义的继承自ClassLoader抽象类的实现Custom ClassLoader。
(1) Bootstrap ClassLoader : 此类并非ClassLoader的子类,在代码中没办法拿到这个类的对象,Sun JDK会在启动时自动加载此类。此加载器会将存放于<JAVA_HOME>\lib目录中的,或者被-Xbootclasspath参数所指定的路径中的,并且是虚拟机识别的(仅按照文件名识别,如 rt.jar 名字不符合的类库即使放在lib目录中也不会被加载)类库加载到虚拟机内存中
(2) Extension ClassLoader : 此加载器会将<JAVA_HOME>\lib\ext目录下的,或者被java.ext.dirs系统变量所指定的路径中的所有类库加载.
(3) App ClassLoader : 此加载器会将用户类路径(ClassPath)上所指定的类库加载。
(4) Custom ClassLoader : 基于自定义的ClassLoader加载非classpath中的jar及目录,还可以在加载之前对class文件做一些动作,例如加密。
- JVM 的ClassLoader采用的是树形结构,除 Bootstrap ClassLoader外都会有父级的ClassLoader。加载类时通常会按照树形结构的原则进行。如果一个类加载器接收到了类加载的请求,它首先把这个请求委托给他的父类加载器去完成,每个层次的类加载器都是如此,因此所有的加载请求都应该传送到顶层的启动类加载器中,只有当父加载器反馈自己无法完成这个加载请求(它在搜索范围中没有找到所需的类)时,子加载器才会尝试自己去加载。 这样做的好处是:java类随着它的类加载器一起具备了一种带有优先级的层次关系。例如类java.lang.Object,它存放在rt.jar中,无论哪个类加载器要加载这个类,最终都会委派给启动类加载器进行加载,因此Object类在程序的各种类加载器环境中都是同一个类。相反,如果用户自己写了一个名为java.lang.Object的类,并放在程序的Classpath中,那系统中将会出现多个不同的Object类,java类型体系中最基础的行为也无法保证,应用程序也会变得一片混乱。
二 . 初始化
java会尽量保证变量在使用前得到恰当的初始化,对于局部变量,如果未初始化会得到编译时的错误,对于成员变量会自动初始化(0,null等)。
可以使用构造方法初始化成员变量,在运行时刻,可以调用方法或者执行某些动作来确定初值。但需要记住一点:无法阻止自动初始化的进行,它在构造方法被调用之前发生。对于所有基本类型和对象引用,包括在定义时已经指定初始值的变量,情况也是一样的.例如如下实例代码,i首先会被置为0,然后替换为指定的初始值7.

public class TestClass(){
int i;//自动初始化赋值为0
public static void main(String[] args){
i = 7;//赋值为7
}
}

1 . 初始化的顺序:在类的内部,变量定义的先后顺序决定了初始化的顺序。即使变量的定义散布于方法定义之间,他们仍会在任何方法(包括构造方法)被调用之前得到初始化
对于如下代码:w3这个引用会被初始化两次,一次在调用构造方法之前,一次在调用期间,这时第一次引用的对象将被丢弃并被垃圾回收.

public class House {
Window w1 = new Window(1);
public House() {
System.out.println("House()");
w3 = new Window(3_3);
}
Window w2 = new Window(2);
public void method() {
System.out.println("method()");
}
Window w3 = new Window(3);
public static void main(String[] args) {
House house = new House();
}
}
class Window {
Window(int order) {
System.out.println("window" + order);
}
}
//输出结果为:
window1
window2
window3
House()
window33

2 . 静态数据的初始化
静态初始化只有在必要的时候才进行,初始化的顺序是先静态对象(如果它们尚未因前面的的对象创建过程而被初始化),而后是“非静态”对象。
示例代码如下:

public class StaticInitailization {
public static void main(String[] args) {
System.out.println("creating new CupBoard() in main");
new CupBoard();
System.out.println("creating new CupBoard() in main");
new CupBoard();
table.f2(1);
cupBoard.f3(1);
}
static Table table = new Table();
static CupBoard cupBoard = new CupBoard();
}
class Bowl {
public Bowl(int i) {
System.out.println("Bowl(" + i + ")");
}
void f1(int i) {
System.out.println("f1(" + i + ")");
}
}
class Table {
static Bowl bowl1 = new Bowl(1);
Table() {
System.out.println("Table()");
bowl2.f1(1);
}
void f2(int i) {
System.out.println("f2(" + i + ")");
}
static Bowl bowl2 = new Bowl(2);
}
class CupBoard {
Bowl bowl3 = new Bowl(3);
static Bowl bowl4 = new Bowl(4);
CupBoard() {
System.out.println("CupBoard()");
bowl4.f1(2);
}
void f3(int i) {
System.out.println("f3(" + i + ")");
}
static Bowl bowl5 = new Bowl(5);
}
// 结果如下:
Bowl(1)
Bowl(2)
Table()
f1(1)
Bowl(4)
Bowl(5)
Bowl(3)
CupBoard()
f1(2)
creating new CupBoard() in main
Bowl(3)
CupBoard()
f1(2)
creating new CupBoard() in main
Bowl(3)
CupBoard()
f1(2)
f2(1)
f3(1)

3 . 对象的创建过程: 假设有个名为Dog 的类
(1) 即使没有显示的使用static关键字,构造方法实际上也是静态方法。因此,当首次创建Dog类的对象时,或者Dog类的静态方法或者静态变量被访问时,java解释器必须先查找类路径,以定位Dog.class文件
(2)载入Dog.class文件(这将创建一个Class对象),有关静态初始化的所有动作都会执行。因此,静态初始化只在类首次加载的时候进行一次
(3)用new Dog 创建对象的时候,首先会在堆上为该对象分配足够的存储空间
(4)这块存储空间会被清零,这将会自动的为该对象的的所有基本数据类型赋初值
(5)执行所有出现于字段定义处的初始化动作。
(6)执行构造方法。
复杂对象调用构造方法的顺序:
(1) 在其他任何事物发生之前,将分配给对象的的存储空间初始化为二进制的零
(2) 调用父类的构造方法
(3) 按照声明顺序调用成员的初始化方法
(4) 调用子类构造方法的主体部分编写构方法注意避免调用其他方法,在构造方法内唯一能安全调用的方法是父类中的final方法(也适用于private方法,他们自动属于final方法)。这些方法不能被override(覆写)
参考书籍:分布式java应用基础与实践--林昊 3.1.2节 类加载机制
参考博客1:深入理解Java:类加载机制及反射
参考博客2:Java中普通代码块,构造代码块,静态代码块区别及代码示例
java 复习整理(五 类加载机制与对象初始化)的更多相关文章
- 《深入理解 Java 虚拟机》学习 -- 类加载机制
<深入理解 Java 虚拟机>学习 -- 类加载机制 1. 概述 虚拟机把描述类的数据从 Class 文件加载到内存,并对数据进行校验.转换解析和初始化,最终形成可以被虚拟机直接使用的 J ...
- [五]类加载机制双亲委派机制 底层代码实现原理 源码分析 java类加载双亲委派机制是如何实现的
Launcher启动类 本文是双亲委派机制的源码分析部分,类加载机制中的双亲委派模型对于jvm的稳定运行是非常重要的 不过源码其实比较简单,接下来简单介绍一下 我们先从启动类说起 有一个Lau ...
- Java魔法堂:类加载机制入了个门
一.前言 当在CMD/SHELL中输入 $ java Main<CR><LF> 后,Main程序就开始运行了,但在运行之前总得先把Main.class及其所依赖的类加载到JVM ...
- JVM类加载机制与对象的生命周期
转载请注明原文地址:http://www.cnblogs.com/ygj0930/p/6536048.html 虚拟机把描述类的数据从Class文件加载到内存,并对数据进行校验.转换解析和初始化,最 ...
- 《深入理解Java虚拟机》虚拟机类加载机制
上节学习回顾 上一节,我们深入到类文件去了解其结构细节,也大概对类文件的编写规则略知一二了,解析来我们就得学习这个类文件是如何被加载到Java虚拟机的,看看有什么引人入胜的奥秘. 本节学习重点 大部分 ...
- java虚拟机之虚拟机类加载机制
此处主要需要知道什么是java虚拟机?java虚拟机如何进行类加载的? java语言本身是编译型和解释型的语言,先对本地的java文件进行编译,编译后会在本地生成一个class文件,而这个生成的cla ...
- 深入理解Java虚拟机:虚拟机类加载机制
目录 7.1 概述 7.2 类加载的时机 类的生命周期 5种情况需要"初始化" 7.3 类加载的过程 1.加载 2.验证 3.准备 4.解析 5.初始化 7.4 类加载器 类与类加 ...
- java 复习整理(一 java简介和基础语法)
现在公司用的是封装太多东西的平台开发,觉着之前学的东西很多都忘了,所以想好好总结回顾一下.之前总是想学很多编程语言像python.s6.node.react,但现在越来越体会到编程语言只是一个开发的工 ...
- 深入理解Java虚拟机笔记——虚拟机类加载机制
目录 概述 动态加载和动态连接 类加载的时机 类的生命周期 被动引用 例子一(调用子类继承父类的字段) 例子二(数组) 例子三(静态常量) 类加载的过程 加载 验证 准备 解析 符号引用 直接引用 初 ...
随机推荐
- 【Python 2 到 3 系列】 print 是函数
v3.0 以前,print一直作为语法结构存在,他是python语法的一部分:这个理解起来可能有点蹩脚,但的确是这样. print 一直被定以为一个statement,也就是说,他跟return/tr ...
- OracleWeblogic12C安装教程
一,安装WebLogic Server 1. 双击exe安装文件 2.准备安装文件 3. 生成向导序列 4. 选择安装路径 5. 开始安装 经过以上步骤,weblogic已经成功安装到了你的电脑上,但 ...
- mysql 存储过程的基本语法知识
1 MySQL中的基本的存储过程 我将其分类为增删改查来逐一的分布来说 增加: //创建一个存储过程 $sql = " CREATE PROCEDURE TABLE_PR2() ---- 注 ...
- linux学习(3)——vim文本编辑工具
(三) vi与vim的最大区别就是编辑一个文本vi不显示颜色,vim显示颜色. 安装: yum install -y vim-enhance Vim有三种模式 A:一般模式 上下左右光标 k j h ...
- 状压DP详解(位运算)
前言: 状压DP是一种非常暴力的做法(有一些可以排除某些状态的除外),例如dp[S][v]中,S可以代表已经访问过的顶点的集合,v可以代表当前所在的顶点为v.S代表的就是一种状态(二进制表示),比如 ...
- POJ 2836 状压DP
Rectangular Covering Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 2727 Accepted: 7 ...
- django-mysqlclient_1193错误
Django 配置 mysqlclient 驱动 1193错误 错误描述: django.db.utils.OperationalError: (1193, "Unknown system ...
- 笔记-爬虫-selenium常用方法
笔记-爬虫-selenium常用方法 1. 查找元素 常用的查找方法 find_element_by_name find_element_by_xpath find_element_by_l ...
- Arch + Win10 EFI 引导重装记录
Lenovo G50-70 BCM43142网卡,Win10原版镜像. 主板调成EFI启动. 制作Win10启动盘,打开UltraISO,文件,打开,选中Win10镜像,启动,写入硬盘映像,格式化,写 ...
- TensorFlow验证码识别
本节我们来用 TensorFlow 来实现一个深度学习模型,用来实现验证码识别的过程,这里我们识别的验证码是图形验证码,首先我们会用标注好的数据来训练一个模型,然后再用模型来实现这个验证码的识别. 验 ...