一、类的生命周期概述
二、类的加载阶段 Loading
1 加载完成的操作
2 二进制流的获取
3 类模型与class实例的位置
反射的使用:
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
public class Test {
public static void main(String[] args) {
try {
Class<?> cls = Class.forName("java.lang.String");
Method[] ms = cls.getDeclaredMethods();
for(Method m : ms) {
String mod = Modifier.toString(m.getModifiers());
System.out.print(mod + " ");
String returnType = m.getReturnType().getSimpleName();
System.out.print(returnType + " ");
System.out.print(m.getName() + "(");
Class<?>[] pt = m.getParameterTypes();
if (pt.length == 0) System.out.print(')');
for (int i = 0; i < pt.length; i++) {
char end = (i == pt.length - 1) ? ')' : ',';
System.out.print(pt[i].getSimpleName() + end);
}
System.out.println();
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
3 数组类的加载
三、类的链接阶段 Linking
1 链接阶段的验证环节 Verification
2 链接阶段的准备环节 Prepare
3 链接阶段的解析环节 Resolution
四、类的初始化阶段 Initialization
1 类的初始化过程
被static final修饰的引用变量是在初始化阶段进行赋值。但也有特例,例如static final修饰的String类型,如果是字面量方式进行赋值,那也是连接环节的准备阶段就进行赋值。或者像这样int a = new Random().nextInt();也是在初始化阶段赋值。
2 <clinit>()的线程安全性
如下是通过<clinit>()实现的死锁:
package com.spd.jvm;
class A {
static {
try {
Thread.sleep(1000);
Class.forName("com.spd.jvm.B");
} catch (InterruptedException | ClassNotFoundException e) {
e.printStackTrace();
}
System.out.println("A finish init.");
}
}
class B {
static {
try {
Thread.sleep(1000);
Class.forName("com.spd.jvm.A");
} catch (InterruptedException | ClassNotFoundException e) {
e.printStackTrace();
}
System.out.println("B finish init.");
}
}
class DeadLockThread extends Thread {
private final char flag;
public DeadLockThread(char flag) {
this.flag = flag;
this.setName("Thread" + flag);
}
public void run() {
try {
Class.forName("com.spd.jvm." + flag);
} catch(ClassNotFoundException e) {
e.printStackTrace();
}
}
}
public class Test {
public static void main(String[] args) {
DeadLockThread a = new DeadLockThread('A');
DeadLockThread b = new DeadLockThread('B');
a.start();
b.start();
}
}
3 类的主动使用和被动使用
主动使用中第八点和被动使用第四点了解一下就行,目前无需掌握。
五、类的卸载 Unloading
六、类加载器的概述
1 概述
2 类加载器的分类
package com.spd.jvm;
class User {
}
public class Test {
public static void main(String[] args) {
User user = new User(); // 隐式加载
try {
Class cls = Class.forName("com.spd.jvm.User"); // 显式加载
ClassLoader.getSystemClassLoader().loadClass("com.spd.jvm.User"); // 显式加载
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
3 类加载器的必要性
七、类加载器的命名空间与类加载器的分类
1 类加载器的命名空间
同一个字节码文件被两个不同的类加载器加载,那就是两个类。
2 类加载器的分类
上面这个图中,除了Bootstrap是用c/c++实现,其余都是用java实现的。
(这个描述咋听起来像装饰模式)
八、关于不同类加载器的一些说明
1 启动类加载器
加入+TraceClassLoading这个参数,就能输出上面这种信息。
2 扩展类加载器
3 系统类加载器
4 用户自定义类加载器
数组对象的类加载器获取后打印出来是null,因为他不需要类加载器,自然也就没有。