我们都知道,在Java语言中,有静态字段和实例字段,但是,它们两者之间的初始化是有区别的。
其中,需要说明的一点就是:静态字段由类调用,实例字段由对象调用!!!
1. 静态字段
static 静态字段 / 静态变量 的初始化过程,由Java虚拟机JVM加载类后,自动进行静态字段初始化。
①静态字段的默认初始化:静态字段设置为其类型的默认值。
②静态字段的声明初始化:静态字段设置为声明时的初始化值。
③静态字段的静态块初始化:依次调用静态块进行初始化。
从源程序的角度看,静态字段以上三种初始化的顺序:
①首先进行默认初始化。
②然后根据声明初始化、静态块初始化这两者在程序中的顺序来依次进行!!!(两者谁先谁后是不一定的)
2. 实例字段
实例字段 / 实例变量 的初始化过程,由new进行实例初始化。
①实例字段的默认初始化:实例字段设置为其类型的默认值。
②实例字段的声明初始化:实例字段设置为声明时的初始化值。
③实例字段的实例构造方法初始化:根据实例构造方法签名,调用实例构造方法进行初始化。
从源程序的角度看,实例字段以上三种初始化的顺序:
①首先必须进行默认初始化。
②然后进行声明初始化。
③最后进行实例构造方法的初始化。
因为实例字段相对来说,比较好理解,所以我们在这里重点对静态字段的初始化进行讲解!!!
我们依次来看下面的五个程序!!!👇👇👇
Program Ⅰ: (没有静态块,静态变量的声明初始化的顺序不同)
class Test1 { public Test1() { System.out.println("Test1实例构造函数之前 a="+Test.a+",b="+Test.b); Test.a++; Test.b++; System.out.println("Test1实例构造函数之后 a="+Test.a+",b="+Test.b); } } public class Test { public static Test1 t=new Test1(); public static int a; public static int b=10; public static void main(String[] args) { System.out.println("最后的结果:a="+Test.a+",b="+Test.b); } }
Program Output Ⅰ:
Program Analysis Ⅰ:
按此顺序初始化静态变量:默认初始化→声明初始化
默认初始化:静态变量按照声明的顺序依次设置为该类型的默认值。
声明初始化:静态变量按声明的顺序依次设置为声明初始化的值,如果没有声明初始化就跳过。
静态字段初始化流程如下:
1. 默认初始化:类被加载后,首先静态字段会进行默认初始化。结果:t=null,a=0,b=0
2. 声明初始化:①首先进行静态字段t的声明初始化,创建Test1的实例,调用实例构造方法,执行之后的结果:a=1,b=1
②然后进行静态字段a和b的声明初始化,因为静态字段a没有声明初始化,所以就跳过,并执行Test.a++, 此时a=1;但是静态字段b由声明初始化,结果b=10。(大家对照这个流程,看一下上面的代码和运行结果)
Program Ⅱ:(没有静态块,静态变量的声明初始化的顺序不同)
class Test1 { public Test1() { System.out.println("Test1实例构造函数之前 a="+Test.a+",b="+Test.b); Test.a++; Test.b++; System.out.println("Test1实例构造函数之后 a="+Test.a+",b="+Test.b); } } public class Test { public static int a; public static int b=10; public static Test1 t=new Test1(); public static void main(String[] args) { System.out.println("最后的结果:a="+Test.a+",b="+Test.b); } }
Program Output Ⅱ:
Program Analysis Ⅱ:
按此顺序初始化静态变量:默认初始化→声明初始化
默认初始化:静态变量按照声明的顺序依次设置为该类型的默认值。
声明初始化:静态变量按声明的顺序依次设置为声明初始化的值,如果没有声明初始化就跳过。
静态字段初始化流程如下:
1. 默认初始化:类被加载后,首先静态字段会进行默认初始化。结果:t=null,a=0,b=0。
2. 声明初始化:①首先进行静态字段a和b的声明初始化,因为静态字段a没有声明初始化,所以就跳过,结果还是a=0;但 静态字段b有声明初始化,所以结果是b=10。
②然后再进行静态字段t的声明初始化,创建Test1的实例,调用实例构造方法,Test.a++,Test.b++,执行 之后的结果是a=1,b=11。(大家对照这个流程,看一下上面的代码和运行结果)
Program Ⅲ:(有静态块,静态块定义在声明初始化语句之后)
class Test1 { public Test1() { System.out.println("Test1实例构造函数之前 a="+Test.a+",b="+Test.b); Test.a++; Test.b++; System.out.println("Test1实例构造函数之后 a="+Test.a+",b="+Test.b); } } public class Test { public static Test1 t=new Test1(); public static int a; public static int b=10; static { a=20; System.out.println("static静态代码块1之后 a="+Test.a+",b="+Test.b); } static { b=30; System.out.println("static静态代码块2之后 a="+Test.a+",b="+Test.b); } public static void main(String[] args) { System.out.println("最后的结果:a="+Test.a+",b="+Test.b); } }
Program Output Ⅲ:
Program Analysis Ⅲ:
按此顺序初始化静态变量:默认初始化→声明初始化→静态代码块初始化
默认初始化:静态变量按照声明的顺序依次设置为该类型的默认值。
声明初始化:静态变量按声明的顺序依次设置为声明初始化的值,如果没有声明初始化就跳过。
静态代码块初始化:按照静态代码块的顺序依次设置静态字段的值。
静态字段初始化流程如下:
1. 默认初始化:类被加载后,首先静态字段会进行默认初始化。 结果:t=null,a=0,b=0。
2. 声明初始化:①首先进行静态字段t的声明初始化,创建Test1的实例,调用实力构造方法,执行之后的结果是a=1,b=1
②进行静态字段a和b的声明初始化,因为静态字段a没有声明初始化,所以就跳过,结果还是a=1;但是静 态字段b有声明初始化,所以结果是b=10。
3. 静态代码块初始化:①首先执行静态代码块1,对静态字段a进行静态块初始化,结果是a=20,b=10。
②然后执行静态代码块2,对静态字段b进行静态块初始化,结果是a=20,b=30。(大家对照这个流程,看一下上面的代码和运行结果)
Program Ⅳ:(有静态块,静态块定义在声明初始化语句之前)
class Test1 { public Test1() { System.out.println("Test1实例构造函数之前 a="+Test.a+",b="+Test.b); Test.a++; Test.b++; System.out.println("Test1实例构造函数之后 a="+Test.a+",b="+Test.b); } } public class Test { static { a=20; System.out.println("static静态代码块1之后 a="+Test.a+",b="+Test.b); } static { b=30; System.out.println("static静态代码块2之后 a="+Test.a+",b="+Test.b); } public static Test1 t=new Test1(); public static int a; public static int b=10; public static void main(String[] args) { System.out.println("最后的结果:a="+Test.a+",b="+Test.b); } }
Program Output Ⅳ:
Program Analysis Ⅳ:
按此顺序初始化静态变量:默认初始化→静态代码块初始化→声明初始化
默认初始化:静态变量按照声明的顺序依次设置为该类型的默认值。
静态代码块初始化:按静态块的顺序依次设置静态字段的值。
声明初始化:静态变量按声明的顺序依次设置为声明初始化的值,如果没有声明初始化就跳过。
静态字段初始化流程如下:
1. 默认初始化:类被加载后,首先静态字段会进行默认初始化。 结果:t=null,a=0,b=0。
2. 静态代码块初始化:①首先执行静态代码块1,对静态字段a进行静态块初始化,结果是a=20,b=0。
②然后执行静态代码块2,对静态字段b进行静态块初始化,结果是a=20,b=30。
3. 声明初始化:①首先进行静态字段t的声明初始化,创建Test1的实例,调用实例构造方法,执行后的结果是a=21,b=31
②然后进行静态字段a和b的声明初始化,因为静态字段a没有声明初始化,所以就跳过,结果还是a=21; 但是静态字段b有声明初始化,所以结果是b=10。(大家对照这个流程,看一下上面的代码和运行结果)
Program Ⅴ:(有静态块,声明初始化语句在两个静态块定义之间)
class Test1 { public Test1() { System.out.println("Test1实例构造函数之前 a="+Test.a+",b="+Test.b); Test.a++; Test.b++; System.out.println("Test1实例构造函数之后 a="+Test.a+",b="+Test.b); } } public class Test { static { a=20; System.out.println("static静态代码块1之后 a="+Test.a+",b="+Test.b); } public static Test1 t=new Test1(); public static int a; public static int b=10; static { b=30; System.out.println("static静态代码块2之后 a="+Test.a+",b="+Test.b); } public static void main(String[] args) { System.out.println("最后的结果:a="+Test.a+",b="+Test.b); } }
Program Output Ⅴ:
Program Analysis Ⅴ:
按此顺序初始化静态变量:默认初始化→静态代码块1初始化→声明初始化→静态代码块2初始化
默认初始化:静态变量按照声明的顺序依次设置为该类型的默认值。
静态代码块初始化:按静态块的顺序依次设置静态字段的值。
声明初始化:静态变量按声明的顺序依次设置为声明初始化的值,如果没有声明初始化就跳过。
静态字段初始化流程如下:
1. 默认初始化:类被加载后,首先静态字段会进行默认初始化。 结果:t=null,a=0,b=0。
2. 静态代码块1初始化:对静态字段a进行静态块初始化,结果a=20,b=0。
3. 声明初始化:①首先进行静态字段t的声明初始化,创建Test1的实例,调用实例构造方法,执行之后结果是a=21,b=1。
②然后进行静态字段a和b的声明初始化,因为静态字段a没有声明初始化,所以就跳过,结果还是a=21; 但是静态字段b有声明初始化,所以结果是b=10。
4. 静态代码块2初始化:对静态字段b进行静态块初始化,结果a=21,b=30。(大家对照这个流程,看一下上面的代码和运行结果)
根据上面这五个Java小程序,大家可能觉得比较多,看起来不舒服,但是静态字段这部分内容还是很重要的!!!
所以希望大家可以耐心的去理解每一个程序代码,对我们后面的Java知识的学习还是有很大帮助的!!!😊😊😊