类加载流程
演示代码:
public class Demo01 {
public static void main(String[] args) {
Demo demo = new Demo();
//3、创建对象
demo.test01();
//18、调用test01方法
}
}
class Demo{
static int a;
//1、a=0
int b;
//4、demo.b=0
int num2 = test01();
//5、调用test01方法
//9、demo.num2=1
static{
System.out.println("1"+a);
//2、打印10
}
{
System.out.println("2"+a);
//10、打印21
System.out.println("2"+b);
//11、打印21
}
public Demo(){
System.out.println("3"+a);
//12、打印31
System.out.println("3"+b);
//13、打印31
test01();
//14、调用test01方法
}
public int test01(){
System.out.println("4"+(a++));
//6、打印40,a=1
//15、打印41,a=2
//19、打印42,a=3
System.out.println("4"+(b++));
//7、打印40,b=1
//16、打印41,b=2
//20、打印42,b=3
return a;
//8、返回1
//17、返回2
//21、返回3
}
}
结果:
1、将所有static加载的属性,代码块分配内存
2、依次对属性赋值,然后执行静态代码块
3、创建对象也是同理
4、先给成员变量划分空间,然后依次赋值
5、由于静态部分已经随着类的加载而全部加载进内存,所以不再执行。执行构造代码块
6、再执行构造函数
据说是华为n年前的题目
public class Demo02 {
//1、将所有static修饰的属性,代码块和方法加载进内存
//2、对static修饰的属性进行初始化
public static int k = 0;
//3、k=0
public static Demo02 t1 = new Demo02("t1");
//4、创建一个Demo02对象为t1赋值,static修饰的属性和代码块已经加载进内存,不再执行
public static Demo02 t2 = new Demo02("t2");
//17、与t1同理,结果为:4:j i=3 n=3;5:构造块 i=4 n=4;6:t2 i=5 n=5
//t2.a=0 t2.j=3
public static int i = print("i");
//18、调用print方法,为i赋值,此时i=6
//22、i=7
public static int n = 99;
//23、n=99
private int a = 0;
//5、k=0 t1.a=0
public int j = print("j");
//6、调用print(String str)为j赋值
//t1.j=1
{
print("构造快");
//10、调用print()函数
}
static{
print("静态块");
//24、调用print方法
}
public Demo02(String str){
System.out.println((++k)+":"+str+" i="+i+" n="+n);
//14、k=3,i=2,n=2; 3:t1 i=2 n=2
++i;
//15、i=3
++n;
//16、n=3
}
public static int print(String str){
System.out.println((++k)+":"+str+" i="+i+" n="+n);
//7、k=1;i,n还没赋值,默认值为0; 1:j i=0 n=0
//11、k=2;i=1,n=1; 2:构造块 i=1 n=1
//19、k=7;i=6,n=6;7:j i=6 n=6
//25、k=8;i=7,n=99;8:静态块 i=7 n=99
++n;
//8、n=1
//12、n=2
//20、n=7
//26、n=100
return ++i;
//9、i=1,返回1
//13、i=2,返回2
//21、i=7,返回7
//27、i=8,返回8
}
public static void main(String[] args) {
//28、结束
//i=8 n=100
}
}
结果:
代码执行按顺序看代码注释
1、这个面试题的难点在于static成员变量的初始化创建了一个对象,需要理解类的加载机制。
类的加载机制
类的加载机制主要分为三个部分:加载,链接,初始化。链接又可以细分为验证,准备和解析。
加载
指把class字节码文件从各个来源通过类加载器装载进内存。
验证
为了保证加载进来的字节流符合虚拟机规范,不会造成安全错误。(这个我也不懂原理,只知道有这么一回事)
准备
(面试题考点)主要为静态变量(注意不是实例变量)分配内存和赋予初值。初值,不是代码中具体写的初始化的值,而是Java虚拟机根据不同变量类型的默认初始值。如基本类型的初值就是0,引用类型初值为null,常量初值为代码中设置的值.
解释
将常量池内的符号引用替换为直接引用。(这个我也不懂原理,只知道有这么一回事)
初始化
(面试题考点)这个阶段对static修饰的变量、代码块进行初始化。如果初始化一个类的时候,其父类还没有初始化,就先对父类初始化。如果含有多个静态变量和静态代码块,就按顺序从上到下执行。
拓展:
内存主要分为四个区:
栈:栈中保存基本数据类型的变量和自定义的对象的引用(不是对象)**,**对象本身都存放在堆区中,被执行的方法的也是pull到栈中,当方法执行完后再push出栈。
堆:所有使用new创建的对象本身都存放在堆中
数据区:存放类中的方法
代码区:static变量和String常量
如果错漏,欢迎指正。