今天考试初始化顺序错了好几题,整理后做一个总结吧。
内容主要有:静态属性变量,变量,静态代码块,构造代码块,构造函数,静态方法,普通方法,子类,父类
初始化顺序:
先声明,后赋值;
先属性,后方法;
先静态,后非静态;
先父类,后子类
——————————————第一个例子——————————————————
先举简单的例子来说:
public class Demo {
static{
System.out.print("静态块top——————\n");
}
public static int k=0;
public static Demo t1=new Demo("t1");
public static int i=print("i");
public static int n=99;
private int a=3;
public int ttt=pri("ttt");
{
System.out.println("构造块");
}
static{
System.out.println("静态块");
}
public Demo(String string) {
System.out.println(string);
}
public int pri(String str){
System.out.println(str);
return 888;
}
private static int print(String string) {
System.out.println(string);
return 1;
}
public static void main(String[] args) {
}
}
****************
先声明:
k=0;
t1=null;
i=0;
n=0;
a=error——先声明静态的,后非静态的,所以这个时候非静态的a还没有声明
这是第一轮声明,声明的时候静态属性都会有系统默认值,顺序是从上往下。
那么声明属性之后静态方法有没有声明?个人觉得应该是声明的(至于先声明静态属性还是静态方法或者
按顺序声明还没想到办法验证,但这并没关系)。因为第一个静态代码块调用下面的静态方法也是可以调用的。
所以下面的静态方法是声明了,但声明并不等于调用执行。
所以上面的代码可以理解成:
静态属性:
k=0;
t1=null;
t2=null;
i=0;
n=0;
静态方法:
第一个static{}
第二个static{}
static的println(string)
main(args)
变量:
a=error
ttt=error
实例方法:
构造块方法=error
构造函数=error
pri=error
说的简单点,第一轮声明静态属性和静态方法,顺序无所谓。
******************
后赋值(静态属性和方法 依照从上往下的顺序执行):
执行static代码块:
static{
System.out.print("静态块top——————\n");
}
k=0;
t1=new StaticTest("t1");
t1要实例化对象,这个怎么执行呢?
初始化的时候依据现在的执行状态生成一个对象,生产对象的之前需要把没有完成的继续完成。
现在的状态是:
输出过一句:静态块top——————
k=0;
t1在初始化
t2=null;
i=0;
n=0;
a=error
ttt=error
构造块方法=error
pri=error
需要完成:
a=0;
ttt=pri("ttt");——调用方法输出"ttt" 方法不用看了,因为只有调用才会执行
初始化之前调用(优先级和变量一样,如果下面还有变量,则会继续赋值变量):
{
System.out.println("构造块");——输出"构造块"
}
初始化:
public Demo(String string) {
System.out.println(string);——输出"t1"
}
i=print("i");
调用print方法:
System.out.println(string);——输出"i"
i=1;
n=99;
static{
System.out.println("静态块");——输出"静态块"
}
进入static的main方法
public static void main(String[] args) {
这个时候变量比如a还没有声明,所以如果想要打印a是会报错的。
为什么说还没有声明?因为Debug的时候,a=error,如果申明了,则会有默认的初始值
}
***************************
这个例子就讲完了。
输出结果:
静态块top——————
ttt
构造块
t1
i
静态块
**
初始化的过程是:
先声明静态属性和方法,静态属性赋值默认值,方法声明但不调用执行
后赋值静态属性和方法,按 顺序 执行,main方法也只是一个静态方法,如果下面还有静态代码块,则执行完main方法后最后还会调用下面的静态代码块。
需要注意和理解的点:
1 静态属性和非静态属性生成一个实例变量(new)的时候,执行未赋值的变量然后初始化,不管静态属性中是否还有未赋值元素
2 静态代码块,静态属性,静态方法优先级一样,按照顺序执行
3 变量和实例方法一起声明,声明后实例方法就可以调用,所以变量赋值的时候可以调用实例方法。
4 优先级:静态属性=静态代码块>mian方法(上面没有体现,可以自己测试)
静态代码块放在静态属性前后,按顺序执行
静态属性 和 main方法比较:先属性,后方法
静态代码块放在main方法前后,都会在main之前执行
优先级:全局变量属性=全局构造代码块>构造方法
构造代码块无论放在构造方法前后,都先执行构造代码块
全局变量属性放在构造代码块前后,按顺序执行
全局变量属性和构造方法:先属性,后方法
所以,如果理解了这个例子,就能明白两个问题:
1 为什么静态方法只能调用静态属性和静态方法?——静态属性和静态方法调用执行的时候,非静态属性和方法都没有声明怎么调用呢?
2 为什么变量和方法依赖于对象——因为实例化对象的时候才执行
——————————————第二个例子——————————————————
这个例子是对上面内容举例和补充,如果能正确写出答案,差不多理解了初始化顺序
public class StaticTest {
static{
print("+++++++++++++");
}
public static int k=0;
public static StaticTest t1=new StaticTest("t1");
public static StaticTest t2=new StaticTest("t2");
public static int i=print("i");
public static int n=99;
private int a=0;
public int ttt=pri("ttt");
{
print("构造块");
}
static{
print("静态块");
}
public int j=print("j");
public StaticTest(String str) {
System.out.println((++k)+":"+str+" i="+i+" n="+n);
++i;
++n;
}
private int pri(String str) {
System.out.println(str);
return 0;
}
private static int print(String str) {
System.out.println((++k)+":"+str+" i="+i+" n="+n);
++n;
return ++i;
}
public static void main(String[] args) {
StaticTest tt=new StaticTest("init");
}
}
*********************
声明:
静态属性:
k=0;
t1=null;
t2=null;
i=0;
n=99;
静态方法:
static{}
print(){}
main(){}
*************
赋值:
static{
print("+++++++++++++");
}
private static int print(String str) {
System.out.println((++k)+":"+str+" i="+i+" n="+n);
++n;
return ++i;
}
执行前:k=0,i=0,n=0;
执行:
输出:1:+++++++++++++ i=0 n=0
k=1;
n=1;
i=1;
k=0;——k又变成0了
t1=new StaticTest("t1");
现在的状态:k=0;i=1,n=1;
执行:
先变量:
a=0;
ttt=pri("ttt");
private int pri(String str) {
System.out.println(str);
return 0;
}
输出:"ttt"
ttt=0;
{
print("构造块");
}
private static int print(String str) {
System.out.println((++k)+":"+str+" i="+i+" n="+n);
++n;
return ++i;
}
输出:1:构造块 i=1 n=1
k=1,i=2,n=2;
j=print("j");
private static int print(String str) {
System.out.println((++k)+":"+str+" i="+i+" n="+n);
++n;
return ++i;
}
输出:2:j i=2 n=2
k=2,i=3,n=3;
初始化:
public StaticTest(String str) {
System.out.println((++k)+":"+str+" i="+i+" n="+n);
++i;
++n;
}
输出:3:t1 i=3 n=3
k=3,i=4,n=4;
t2=new StaticTest("t2");
现在的状态:k=3,i=4,n=4;
执行:
先变量:
a=0;
ttt=pri("ttt");
private int pri(String str) {
System.out.println(str);
return 0;
}
输出:"ttt"
ttt=0;
{
print("构造块");
}
private static int print(String str) {
System.out.println((++k)+":"+str+" i="+i+" n="+n);
++n;
return ++i;
}
4:构造块 i=4 n=4
k=4,i=5,n=5;
j=print("j");
private static int print(String str) {
System.out.println((++k)+":"+str+" i="+i+" n="+n);
++n;
return ++i;
}
5:j i=5 n=5
k=5,i=6,n=6;
初始化:
public StaticTest(String str) {
System.out.println((++k)+":"+str+" i="+i+" n="+n);
++i;
++n;
}
6:t2 i=6 n=6
k=6,i=7,n=7;
i=print("i");
private static int print(String str) {
System.out.println((++k)+":"+str+" i="+i+" n="+n);
++n;
return ++i;
}
输出:7:i i=7 n=7
k=7,n=8,i=8;
i=8;
n=99;
static{
print("静态块");
private static int print(String str) {
System.out.println((++k)+":"+str+" i="+i+" n="+n);
++n;
return ++i;
}
8:静态块 i=8 n=99
k=8,i=9,n=100;
}
public static void main(String[] args) {
StaticTest tt=new StaticTest("init");
现在的状态:k=8,i=9,n=100;
执行:
先变量:
a=0;
ttt=pri("ttt");
private int pri(String str) {
System.out.println(str);
return 0;
}
输出:"ttt"
ttt=0;
{
print("构造块");
}
private static int print(String str) {
System.out.println((++k)+":"+str+" i="+i+" n="+n);
++n;
return ++i;
}
9:构造块 i=9 n=100
k=9,i=10,n=101;
j=print("j");
private static int print(String str) {
System.out.println((++k)+":"+str+" i="+i+" n="+n);
++n;
return ++i;
}
10:j i=10 n=101
k=10,i=11,n=102;
初始化:
public StaticTest(String str) {
System.out.println((++k)+":"+str+" i="+i+" n="+n);
++i;
++n;
}
11:init i=11 n=102
k=11,i=12,n=103;
}
结果:
1:+++++++++++++ i=0 n=0
ttt
1:构造块 i=1 n=1
2:j i=2 n=2
3:t1 i=3 n=3
ttt
4:构造块 i=4 n=4
5:j i=5 n=5
6:t2 i=6 n=6
7:i i=7 n=7
8:静态块 i=8 n=99
ttt
9:构造块 i=9 n=100
10:j i=10 n=101
11:init i=11 n=102
*****
——————————————第三个例子——————————————————
class Parent {
public static String p_StaticField = "父类--静态变量";
public String p_Field = "父类--变量";
static {
System.out.println(p_StaticField);
System.out.println("父类--静态初始化块");
}
{
System.out.println(p_Field);
System.out.println("父类--初始化块");
}
public Parent() {
System.out.println("父类--构造器");
}
}
public class SubClass extends Parent {
public static String s_StaticField = "子类--静态变量";
public String s_Field = "子类--变量";
static {
System.out.println(s_StaticField);
System.out.println("子类--静态初始化块");
}
{
System.out.println(s_Field);
System.out.println("子类--初始化块");
}
public SubClass() {
System.out.println("子类--构造器");
}
public static void main(String[] args) {
new SubClass();
}
}
结果:
"父类--静态变量"
"父类--静态初始化块"
"子类--静态变量"
"子类--静态初始化块"
"父类--变量"
"父类--初始化块"
"父类--构造器"
"子类--变量"
"子类--初始化块"
"子类--构造器"
*********
继承的时候,先父类,后子类
加载子类之前需要先加载父类,问题是调用子类的构造函数之前,是先调用子类的构造块 还是先调用父类的构造块和构造函数?事实是系统调用是先调用父类的构造块,父类的全部调用好了,再处理子类
——————————————第四个例子——————————————————
public class TestOrder {
public static TestA a = new TestA();
static {
System.out.println("静态初始化块");
}
public static TestB b = new TestB();
public static void main(String[] args) {
new TestOrder();
}
}
class TestA {
public TestA() {
System.out.println("Test--A");
}
}
class TestB {
public TestB() {
System.out.println("Test--B");
}
}
结果:
"Test--A"
"静态初始化块"
内容主要有:静态属性变量,变量,静态代码块,构造代码块,构造函数,静态方法,普通方法,子类,父类
初始化顺序:
先声明,后赋值;
先属性,后方法;
先静态,后非静态;
先父类,后子类
——————————————第一个例子——————————————————
先举简单的例子来说:
public class Demo {
static{
System.out.print("静态块top——————\n");
}
public static int k=0;
public static Demo t1=new Demo("t1");
public static int i=print("i");
public static int n=99;
private int a=3;
public int ttt=pri("ttt");
{
System.out.println("构造块");
}
static{
System.out.println("静态块");
}
public Demo(String string) {
System.out.println(string);
}
public int pri(String str){
System.out.println(str);
return 888;
}
private static int print(String string) {
System.out.println(string);
return 1;
}
public static void main(String[] args) {
}
}
****************
先声明:
k=0;
t1=null;
i=0;
n=0;
a=error——先声明静态的,后非静态的,所以这个时候非静态的a还没有声明
这是第一轮声明,声明的时候静态属性都会有系统默认值,顺序是从上往下。
那么声明属性之后静态方法有没有声明?个人觉得应该是声明的(至于先声明静态属性还是静态方法或者
按顺序声明还没想到办法验证,但这并没关系)。因为第一个静态代码块调用下面的静态方法也是可以调用的。
所以下面的静态方法是声明了,但声明并不等于调用执行。
所以上面的代码可以理解成:
静态属性:
k=0;
t1=null;
t2=null;
i=0;
n=0;
静态方法:
第一个static{}
第二个static{}
static的println(string)
main(args)
变量:
a=error
ttt=error
实例方法:
构造块方法=error
构造函数=error
pri=error
说的简单点,第一轮声明静态属性和静态方法,顺序无所谓。
******************
后赋值(静态属性和方法 依照从上往下的顺序执行):
执行static代码块:
static{
System.out.print("静态块top——————\n");
}
k=0;
t1=new StaticTest("t1");
t1要实例化对象,这个怎么执行呢?
初始化的时候依据现在的执行状态生成一个对象,生产对象的之前需要把没有完成的继续完成。
现在的状态是:
输出过一句:静态块top——————
k=0;
t1在初始化
t2=null;
i=0;
n=0;
a=error
ttt=error
构造块方法=error
pri=error
需要完成:
a=0;
ttt=pri("ttt");——调用方法输出"ttt" 方法不用看了,因为只有调用才会执行
初始化之前调用(优先级和变量一样,如果下面还有变量,则会继续赋值变量):
{
System.out.println("构造块");——输出"构造块"
}
初始化:
public Demo(String string) {
System.out.println(string);——输出"t1"
}
i=print("i");
调用print方法:
System.out.println(string);——输出"i"
i=1;
n=99;
static{
System.out.println("静态块");——输出"静态块"
}
进入static的main方法
public static void main(String[] args) {
这个时候变量比如a还没有声明,所以如果想要打印a是会报错的。
为什么说还没有声明?因为Debug的时候,a=error,如果申明了,则会有默认的初始值
}
***************************
这个例子就讲完了。
输出结果:
静态块top——————
ttt
构造块
t1
i
静态块
**
初始化的过程是:
先声明静态属性和方法,静态属性赋值默认值,方法声明但不调用执行
后赋值静态属性和方法,按 顺序 执行,main方法也只是一个静态方法,如果下面还有静态代码块,则执行完main方法后最后还会调用下面的静态代码块。
需要注意和理解的点:
1 静态属性和非静态属性生成一个实例变量(new)的时候,执行未赋值的变量然后初始化,不管静态属性中是否还有未赋值元素
2 静态代码块,静态属性,静态方法优先级一样,按照顺序执行
3 变量和实例方法一起声明,声明后实例方法就可以调用,所以变量赋值的时候可以调用实例方法。
4 优先级:静态属性=静态代码块>mian方法(上面没有体现,可以自己测试)
静态代码块放在静态属性前后,按顺序执行
静态属性 和 main方法比较:先属性,后方法
静态代码块放在main方法前后,都会在main之前执行
优先级:全局变量属性=全局构造代码块>构造方法
构造代码块无论放在构造方法前后,都先执行构造代码块
全局变量属性放在构造代码块前后,按顺序执行
全局变量属性和构造方法:先属性,后方法
所以,如果理解了这个例子,就能明白两个问题:
1 为什么静态方法只能调用静态属性和静态方法?——静态属性和静态方法调用执行的时候,非静态属性和方法都没有声明怎么调用呢?
2 为什么变量和方法依赖于对象——因为实例化对象的时候才执行
——————————————第二个例子——————————————————
这个例子是对上面内容举例和补充,如果能正确写出答案,差不多理解了初始化顺序
public class StaticTest {
static{
print("+++++++++++++");
}
public static int k=0;
public static StaticTest t1=new StaticTest("t1");
public static StaticTest t2=new StaticTest("t2");
public static int i=print("i");
public static int n=99;
private int a=0;
public int ttt=pri("ttt");
{
print("构造块");
}
static{
print("静态块");
}
public int j=print("j");
public StaticTest(String str) {
System.out.println((++k)+":"+str+" i="+i+" n="+n);
++i;
++n;
}
private int pri(String str) {
System.out.println(str);
return 0;
}
private static int print(String str) {
System.out.println((++k)+":"+str+" i="+i+" n="+n);
++n;
return ++i;
}
public static void main(String[] args) {
StaticTest tt=new StaticTest("init");
}
}
*********************
声明:
静态属性:
k=0;
t1=null;
t2=null;
i=0;
n=99;
静态方法:
static{}
print(){}
main(){}
*************
赋值:
static{
print("+++++++++++++");
}
private static int print(String str) {
System.out.println((++k)+":"+str+" i="+i+" n="+n);
++n;
return ++i;
}
执行前:k=0,i=0,n=0;
执行:
输出:1:+++++++++++++ i=0 n=0
k=1;
n=1;
i=1;
k=0;——k又变成0了
t1=new StaticTest("t1");
现在的状态:k=0;i=1,n=1;
执行:
先变量:
a=0;
ttt=pri("ttt");
private int pri(String str) {
System.out.println(str);
return 0;
}
输出:"ttt"
ttt=0;
{
print("构造块");
}
private static int print(String str) {
System.out.println((++k)+":"+str+" i="+i+" n="+n);
++n;
return ++i;
}
输出:1:构造块 i=1 n=1
k=1,i=2,n=2;
j=print("j");
private static int print(String str) {
System.out.println((++k)+":"+str+" i="+i+" n="+n);
++n;
return ++i;
}
输出:2:j i=2 n=2
k=2,i=3,n=3;
初始化:
public StaticTest(String str) {
System.out.println((++k)+":"+str+" i="+i+" n="+n);
++i;
++n;
}
输出:3:t1 i=3 n=3
k=3,i=4,n=4;
t2=new StaticTest("t2");
现在的状态:k=3,i=4,n=4;
执行:
先变量:
a=0;
ttt=pri("ttt");
private int pri(String str) {
System.out.println(str);
return 0;
}
输出:"ttt"
ttt=0;
{
print("构造块");
}
private static int print(String str) {
System.out.println((++k)+":"+str+" i="+i+" n="+n);
++n;
return ++i;
}
4:构造块 i=4 n=4
k=4,i=5,n=5;
j=print("j");
private static int print(String str) {
System.out.println((++k)+":"+str+" i="+i+" n="+n);
++n;
return ++i;
}
5:j i=5 n=5
k=5,i=6,n=6;
初始化:
public StaticTest(String str) {
System.out.println((++k)+":"+str+" i="+i+" n="+n);
++i;
++n;
}
6:t2 i=6 n=6
k=6,i=7,n=7;
i=print("i");
private static int print(String str) {
System.out.println((++k)+":"+str+" i="+i+" n="+n);
++n;
return ++i;
}
输出:7:i i=7 n=7
k=7,n=8,i=8;
i=8;
n=99;
static{
print("静态块");
private static int print(String str) {
System.out.println((++k)+":"+str+" i="+i+" n="+n);
++n;
return ++i;
}
8:静态块 i=8 n=99
k=8,i=9,n=100;
}
public static void main(String[] args) {
StaticTest tt=new StaticTest("init");
现在的状态:k=8,i=9,n=100;
执行:
先变量:
a=0;
ttt=pri("ttt");
private int pri(String str) {
System.out.println(str);
return 0;
}
输出:"ttt"
ttt=0;
{
print("构造块");
}
private static int print(String str) {
System.out.println((++k)+":"+str+" i="+i+" n="+n);
++n;
return ++i;
}
9:构造块 i=9 n=100
k=9,i=10,n=101;
j=print("j");
private static int print(String str) {
System.out.println((++k)+":"+str+" i="+i+" n="+n);
++n;
return ++i;
}
10:j i=10 n=101
k=10,i=11,n=102;
初始化:
public StaticTest(String str) {
System.out.println((++k)+":"+str+" i="+i+" n="+n);
++i;
++n;
}
11:init i=11 n=102
k=11,i=12,n=103;
}
结果:
1:+++++++++++++ i=0 n=0
ttt
1:构造块 i=1 n=1
2:j i=2 n=2
3:t1 i=3 n=3
ttt
4:构造块 i=4 n=4
5:j i=5 n=5
6:t2 i=6 n=6
7:i i=7 n=7
8:静态块 i=8 n=99
ttt
9:构造块 i=9 n=100
10:j i=10 n=101
11:init i=11 n=102
*****
——————————————第三个例子——————————————————
class Parent {
public static String p_StaticField = "父类--静态变量";
public String p_Field = "父类--变量";
static {
System.out.println(p_StaticField);
System.out.println("父类--静态初始化块");
}
{
System.out.println(p_Field);
System.out.println("父类--初始化块");
}
public Parent() {
System.out.println("父类--构造器");
}
}
public class SubClass extends Parent {
public static String s_StaticField = "子类--静态变量";
public String s_Field = "子类--变量";
static {
System.out.println(s_StaticField);
System.out.println("子类--静态初始化块");
}
{
System.out.println(s_Field);
System.out.println("子类--初始化块");
}
public SubClass() {
System.out.println("子类--构造器");
}
public static void main(String[] args) {
new SubClass();
}
}
结果:
"父类--静态变量"
"父类--静态初始化块"
"子类--静态变量"
"子类--静态初始化块"
"父类--变量"
"父类--初始化块"
"父类--构造器"
"子类--变量"
"子类--初始化块"
"子类--构造器"
*********
继承的时候,先父类,后子类
加载子类之前需要先加载父类,问题是调用子类的构造函数之前,是先调用子类的构造块 还是先调用父类的构造块和构造函数?事实是系统调用是先调用父类的构造块,父类的全部调用好了,再处理子类
——————————————第四个例子——————————————————
public class TestOrder {
public static TestA a = new TestA();
static {
System.out.println("静态初始化块");
}
public static TestB b = new TestB();
public static void main(String[] args) {
new TestOrder();
}
}
class TestA {
public TestA() {
System.out.println("Test--A");
}
}
class TestB {
public TestB() {
System.out.println("Test--B");
}
}
结果:
"Test--A"
"静态初始化块"
"Test--B"
——————————————第五个例子——————————————————
class HelloA { public HelloA() { System.out.println("HelloA"); } { System.out.println("I'm A class"); } static { System.out.println("static A"); } } public class HelloB extends HelloA { public HelloB() { System.out.println("HelloB"); } { System.out.println("I'm B class"); } static { System.out.println("static B"); } public static void main(String[] args) { new HelloB(); } }结果:
static A static B I'm A class HelloA I'm B class HelloB