类加载机制
类加载的过程
类加载的过程包括了加载、验证、准备、解析、初始化五个阶段
在这五个阶段中,加载、验证、准备和初始化这四个阶段发生的顺序是确定的,而解析阶段则不一定,它在某些情况下可以在初始化阶段之后开始,这是为了支持Java语言的运行时绑定(也成为动态绑定或晚期绑定)。
另外注意这里的几个阶段是按顺序开始,而不是按顺序进行或完成,因为这些阶段通常都是互相交叉地混合进行的,通常在一个阶段执行的过程中调用或激活另一个阶段。
加载
加载时类加载过程的第一个阶段,在加载阶段,虚拟机需要完成以下三件事情:
1、通过一个类的全限定名来获取其定义的二进制字节流。
2、将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构。
3、在Java堆中生成一个代表这个类的java.lang.Class对象,作为对方法区中这些数据的访问入口。
双亲委派模型:

双亲委派模型的工作流程:
如果一个类加载器接受到了类加载的请求,它首先不会自己尝试去加载这个类,而是把请求委托给父加载器去完成,依次向上。
因此,所有的类加载请求最终都应该被传递到顶层的启动类加载器当中,当父类加载器在它的搜索范围中没有找到所需要的类,即无法完成加载时,子类加载器才会去尝试加载该类。
双亲委派模型的好处:
明显的好处是:Java类随着它的类加载器一起具备了一种带优先级的层次关系,有利于保证Java程序的稳定性。
比如:类 java.lang.Object 类存放在JDK\jre\lib下的rt.jar之中,因此无论是哪个类加载器要加载此类,最终都会委派给启动类加载器进行加载,这边保证了Object类在程序中的各种类加载器中都是同一个类。
public class Code_04_SerializeAndReconstructTree {
public static class Node {
public int value;
public Node left;
public Node right;
public Node(int data) {
this.value = data;
}
}
//按照先序遍历的方式进行序列化
public static String serialByPre(Node head) {
if (head == null) {//节点为空,则用 # 进行占位
return "#!";
}
String res = head.value + "!";//节点不为空,打印节点的值,然后用!进行分隔
res += serialByPre(head.left);//左树得到的字符串
res += serialByPre(head.right);//右树得到的字符串
return res;//最后返回整个字符串
}
//按照先序遍历的方式,进行反序列化
public static Node reconByPreString(String preStr) {
String[] values = preStr.split("!");//将字符串中的元素按照分隔符进行分割
Queue<String> queue = new LinkedList<String>();//新建一个队列
for (int i = 0; i != values.length; i++) {//将分割出来的节点数值,添加到队列当中
queue.offer(values[i]);
}
return reconPreOrder(queue);
}
//通过字符串,重建出整棵树
public static Node reconPreOrder(Queue<String> queue) {//传入参数为一个队列
String value = queue.poll();//队列弹出一个值
if (value.equals("#")) {//当前节点值为 # 则当前节点为null
return null;
}
Node head = new Node(Integer.valueOf(value));//先新建头节点
head.left = reconPreOrder(queue);//交给左子树去消费这个队列
head.right = reconPreOrder(queue);//交给右子树去消费这个队列
return head;
}
/**
* description: 按层进行序列化
**/
public static String serialByLevel(Node head) {
if (head == null) {
return "#!";
}
String res = head.value + "!";
Queue<Node> queue = new LinkedList<Node>();
queue.offer(head);
while (!queue.isEmpty()) {
head = queue.poll();
if (head.left != null) {
res += head.left.value + "!";
queue.offer(head.left);
} else {
res += "#!";
}
if (head.right != null) {
res += head.right.value + "!";
queue.offer(head.right);
} else {
res += "#!";
}
}
return res;
}
/**
* description: 按层进行反序列化
**/
public static Node reconByLevelString(String levelStr) {
String[] values = levelStr.split("!");
int index = 0;
Node head = generateNodeByString(values[index++]);
Queue<Node> queue = new LinkedList<Node>();
if (head != null) {
queue.offer(head);
}
Node node = null;
while (!queue.isEmpty()) {
node = queue.poll();
node.left = generateNodeByString(values[index++]);
node.right = generateNodeByString(values[index++]);
if (node.left != null) {
queue.offer(node.left);
}
if (node.right != null) {
queue.offer(node.right);
}
}
return head;
}
public static Node generateNodeByString(String val) {
if (val.equals("#")) {
return null;
}
return new Node(Integer.valueOf(val));
}
/**
* description: 打印二叉树
**/
// for test -- print tree
public static void printTree(Node head) {
System.out.println("Binary Tree:");
printInOrder(head, 0, "H", 17);
System.out.println();
}
public static void printInOrder(Node head, int height, String to, int len) {
if (head == null) {
return;
}
printInOrder(head.right, height + 1, "v", len);
String val = to + head.value + to;
int lenM = val.length();
int lenL = (len - lenM) / 2;
int lenR = len - lenM - lenL;
val = getSpace(lenL) + val + getSpace(lenR);
System.out.println(getSpace(height * len) + val);
printInOrder(head.left, height + 1, "^", len);
}
public static String getSpace(int num) {
String space = " ";
StringBuffer buf = new StringBuffer("");
for (int i = 0; i < num; i++) {
buf.append(space);
}
return buf.toString();
}
public static void main(String[] args) {
Node head = null;
printTree(head);
String pre = serialByPre(head);
System.out.println("serialize tree by pre-order: " + pre);
head = reconByPreString(pre);
System.out.print("reconstruct tree by pre-order, ");
printTree(head);
String level = serialByLevel(head);
System.out.println("serialize tree by level: " + level);
head = reconByLevelString(level);
System.out.print("reconstruct tree by level, ");
printTree(head);
System.out.println("====================================");
head = new Node(1);
printTree(head);
pre = serialByPre(head);
System.out.println("serialize tree by pre-order: " + pre);
head = reconByPreString(pre);
System.out.print("reconstruct tree by pre-order, ");
printTree(head);
level = serialByLevel(head);
System.out.println("serialize tree by level: " + level);
head = reconByLevelString(level);
System.out.print("reconstruct tree by level, ");
printTree(head);
System.out.println("====================================");
head = new Node(1);
head.left = new Node(2);
head.right = new Node(3);
head.left.left = new Node(4);
head.right.right = new Node(5);
printTree(head);
pre = serialByPre(head);
System.out.println("serialize tree by pre-order: " + pre);
head = reconByPreString(pre);
System.out.print("reconstruct tree by pre-order, ");
printTree(head);
level = serialByLevel(head);
System.out.println("serialize tree by level: " + level);
head = reconByLevelString(level);
System.out.print("reconstruct tree by level, ");
printTree(head);
System.out.println("====================================");
head = new Node(100);
head.left = new Node(21);
head.left.left = new Node(37);
head.right = new Node(-42);
head.right.left = new Node(0);
head.right.right = new Node(666);
printTree(head);
pre = serialByPre(head);
System.out.println("serialize tree by pre-order: " + pre);
head = reconByPreString(pre);
System.out.print("reconstruct tree by pre-order, ");
printTree(head);
level = serialByLevel(head);
System.out.println("serialize tree by level: " + level);
head = reconByLevelString(level);
System.out.print("reconstruct tree by level, ");
printTree(head);
System.out.println("====================================");
}
}
参考资料: 类加载机制 类初始化 ClassLoader详解 https://blog.csdn.net/briblue/article/details/54973413