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虚拟机笔记——虚拟机类加载机制
目录 概述 动态加载和动态连接 类加载的时机 类的生命周期 被动引用 例子一(调用子类继承父类的字段) 例子二(数组) 例子三(静态常量) 类加载的过程 加载 验证 准备 解析 符号引用 直接引用 初 ...
随机推荐
- give me something new 无用但有趣
屏保系列 http://www.asty.org/cmatrix/dist/cmatrix-1.2a.tar.gz //数码雨 libaa-bin //燃烧 海洋馆 http://search.cp ...
- 深入理解yii2之RBAC(模块化系统)
一.前言 上一篇文章我们已经大致谈过RBAC到底是什么和yii2底层RBAC接口的分析. 下面我深入理解一下RBAC权限分配,深入理解下yii2底层RBAC扩展,以及它是如何针对模块化系统的开发的? ...
- 【Hadoop/Hive/mapreduce】系列之如何删除HIVE 表格的分区
今天的一个业务场景就是要把三年的数据从第一天不停的融合起来,每一天作为表格一个新的分区.由于空间有限,数据量很大,可能每天数据都是几十个G的大小.所以我需要做的一点就是在融合这一天之后,删除一天的分区 ...
- springboot 入门2 开发环境与生产环境采用不同配置问题
目开发中我们通常有两套配置信息 分别配置了我们的数据源信息等? 那么我们要如何不通过修改配置文件大量配置来实现简单的修改与配置来实现相关配置加载功能 首先springboot 有一个核心的配置文件a ...
- javascript数组&省市联动分别用js数组和JSON实现
1.定义数组的三种方式: **数组可以存放不同的数据类型 第一种: var arr=[1,2,3]; var arr=[1,"2",true]; 第二种: 使用内置对象 ...
- python语法root=Tkinter.Tk()
1. Tkinter 是一个python模块,是一个调用Tcl/Tk的接口,它是一个跨平台的脚本图形界面接口.Tkinter不是唯一的python图形编程接口,但是是 其中比较流行的一个.最大的特点是 ...
- PyCharm 解决有些库(函数)没有代码提示
问题描述: 如图,当输入 im. 没有智能提示第三库相应的函数或其他提示. 解决方案: python是动态强类型语言,IDE无法判断Image.open("panda.png")的 ...
- js 请求异常重连或断线后联网重连机制(ajax)
转到到 https://blog.csdn.net/mengtoumingren/article/details/80296788
- python基础实践(四)
# -*- coding:utf-8 -*-# Author:sweeping-monkwhy = "为什么要组织列表?"print(why)Chicken_soup = &quo ...
- 孤荷凌寒自学python第三十六天文件内容的迭代操作
孤荷凌寒自学python第三十六天python的文件操作对文件内容的迭代操作 (完整学习过程屏幕记录视频地址在文末,手写笔记在文末) 一.os模块的其它文件操作方法补充 1 os.remove(文件 ...