JVM的内存区域划分_crazy_xieyi的博客-CSDN博客
文章目录
1.加载
2.验证
public static int value = 123;
//它是初始化 value 的 int 值为 0,而非 123。
4.解析
这段代码的输出结果是什么?
class A{
public A(){
System.out.println("A的构造方法");
}
{
System.out.println("A的构造代码块");
}
static {
System.out.println("A的静态代码块");
}
}
class B extends A{
public B(){
System.out.println("B的构造方法");
}
{
System.out.println("B的构造代码块");
}
static {
System.out.println("B的静态代码块");
}
}
public class test extends B{
public static void main(String[] args) {
new test();
new test();
}
}
解析:
我们的程序是从main开始执行的,那么main这里是test方法,所以,要执行main,就要先加载test。也就是说,在加载test类的时候,此时还没执行main。
test继承自B,要加载test,那么就要先加载B;
B继承自A,要加载B,那么就要先加载A;
总之,只要这个类被用到了,就要先加载这个类(实例化、调用方法、调用静态方法,被继承...都算被用到)。
然后,要想要构造test,就得先构造B,要想构造B,就得先构造A,那么对于A来说,构造过程 = 构造代码块的执行 + 构造方法的执行。
还有,静态的只执行一次,所以输出结果是:
双亲委派模型是类加载中的一个环节,这环节处于Loading阶段。
双亲委派模型,描述的就是JVM中的类加载器,如何根据类的全限定名( java.lang.String )找到.class文件的过程。
JVM里提供了专门的对象,叫做类加载器,负责进行类加载.当然找文件的过程也是类加载器来负责的。
.class 文件,可能放置的位置有很多.有的要放到JDK目录里,有的放到项目目录里,还有的在其他特定位置,因此JVM里面提供了多个类加载器,每个类加载器负责一个片区。
默认的类加载器主要是三个:
1.BootStrapClassLoader负责加载标准库中的类(String, ArrayList, Random, Scanner..)
2.ExtensionClassLoader负责加载JDK扩展的类.(现在很少会用到)
3.ApplicationClassLoader 负责加载当前项目目录中的类~~
其实程序猿还可以自定义类加载器,来加载其他目录中的类。Tomcat就自定义了类加载器,用来专门加载 webapps里面的.class 。双亲委派模型,就描述了这个找目录过程,也就是上述类加载器是如何配合的。
1.加载java.lang.String
a.程序启动,先进入ApplicationClassLoader类加载器
b.ApplicationClassLoader就会检查下,它的父加载器是否已经加载过了.如果没有,就调用父类加载器ExtensionClassLoader
c. ExtensionClassLoader也会检查下,它的父加载器是否加载过了.如果没有,就调用父类加载器BootStrapClassLoader
d.BootStrapClassLoader也会检查下,它的父加载器是否加载过,自己没有父亲~~于是自己扫描自己负责的目录
e. java.lang.String这个类在标准库中能找到! 直接由BootStrapClassLoader负责后续的加载过程.查找环节就结束了
2.加载自己写的test类
a.程序启动,先进入ApplicationClassLoader类加载器
b.ApplicationClassLoader就会检查下,它的父加载器是否已经加载过了.如果没有,就调用父类加载器ExtensionClassLoader
c. ExtensionClassLoader也会检查下,它的父加载器是否加载过了.如果没有,就调用父类加载器BootStrapClassLoader
d.BootStrapClassLoader也会检查下,它的父加载器是否加载过,自己没有父亲~~于是自己扫描自己负责的目录,如果没有扫描到,就回到子加载器继续扫描。
e.ExtensionClassLoader也扫描自己的目录,如果没有扫描到,就回到子加载器继续扫描。
f.ApplicationClassLoader也扫描自己负责的目录,能找到test类,于是进行后续加载,查找目录的环节结束。