众所周知 在android中static 修饰的会被称之为静态常量,静态变量,静态方法 ,还有就是静态代码块,用static{ // 代码块 非static修饰的方法,变量,常量, 是不能再静态代码块中使用的 } 表示。
static修饰的 是跟着类走的, 而不是跟随对象,这个大家都是知道的。 那么大家是否知道它们之间的运行顺序的关系呢? 今天, 我就给大家简单讲解一下吧。
静态常量,静态变量,静态方法, 大家都知道是通过类名直接调用的(例如:Demo.getStatic() )。但是静态代码块 大家都没有主动调用过 对吧。 那它 到底什么时候被执行呢? 让我来揭晓吧, 其实只要你的代码在任意地方,动用了静态代码块所属的类中的 任意东西, 那么该静态代码块 就会马上执行(说白了就是 静态代码块是这个类最先执行的代码, 但前提是你要使用这个类, 不使用的话, 这个类中的静态代码块是不会执行的 与静态变量相比就是看代码编写的前后顺序,和静态方法有很大的区别)。 当一个类中 有多个静态代码块的时候,是按照代码编写的上下顺序先后执行的。
静态代码块 与 静态变量之间的关系:
如果你想正确使用两者的话, 个人建议 你必须把静态变量定义在静态代码块的前面, 因为两个的执行是会根据代码编写的顺序来决定的。这个比较难理解, 我来举个例子吧, 情况下面代码:
public class Demo{
public static int i;
static{
i = 20;
//这里的i, 是可以被用作运算的。
}
}
这时候如果你在main函数输出i,那么i=20;
public class Demo{
static{
i = 20;
//这里的i, 是不能被用作运算的, 因为本质上 i 还未被定义
}
public static int i;
}
这时候如果你在main函数输出i,那么i=20;
public class Demo{
static{
i = 20;
//这里的i, 是不能被用作运算的, 因为本质上 i 还未被定义
}
public static int i = 1;
}
//但是如果我们给静态的i附上一个初始值后,那么结果就变了。
这时候如果你在main函数输出i,那么i=1;
上述的代码 就其实就是进一步说明静态变量 和static修改的静态代码块 运行的顺序是根据代码编写的先后, 而且第二种写法毫无意义。 未了避免出现不必要的麻烦, 本人强制建议, 不管是否有在静态代码块中使用 静态变量, 都应当把静态变量写在 静态代码块的上方。静态常量的情况 和静态变量是一样, 这里就不在做说明了。
1、执行顺序
1.1、一个类中的初始化顺序
类内容(静态变量、静态初始化块) => 实例内容(变量、初始化块、构造器)
1.2、两个具有继承关系类的初始化顺序
父类的(静态变量、静态初始化块)=> 子类的(静态变量、静态初始化块)=> 父类的(变量、初始化块、构造器)=> 子类的(变量、初始化块、构造器)
示例如下:(结果见注释)
1class A { 2public A() { 3System.out.println("Constructor A."); 4 } 5 6 { 7System.out.println("Instance Block A."); 8 } 9static {10System.out.println("Static Block A.");11 }1213publicstaticvoid main(String[] args) {14newA();/*15 * Static Block A. Instance Block A. Constructor A.16*/17 }18}1920classBextends A {21public B() {22System.out.println("Constructor B.");23 }2425 {26System.out.println("Instance Block B.");27 }28static {29System.out.println("Static Block B.");30 }3132publicstaticvoid main(String[] args) {33newA();/*34 * Static Block A. Static Block B. Instance Block A. Constructor A.35*/36 System.out.println();37newB();/*38 * Instance Block A. Constructor A. Instance Block B. Constructor B.39*/// 静态成员和静态初始化块只会执行一次。40 }41}
2、对变量值的影响
一个变量,若显示初始化、初始化块对该变量赋值、构造方法对该变量赋值同时存在,则变量最终值如何确定?按1节中所述的执行顺序确定。
这里考虑初始化块在变量定义之前的情形,此时会造成迷惑。
初始化块可以对在它之后定义的变量赋值,但不能访问(如打印)。如:
1static {2a = 3;3// int b=a;//Cannot reference a field before it is defined4// System.out.println(a);//Cannot reference a field before it is defined5 }6staticinta = 1;
“对变量值的影响”是指 对变量赋值的初始化块位于变量定义之前 时,变量的最终值根据变量定义时是否显示初始化而会有不同结果(若初始化块位于变量定义之后,那么变量的值显然很容易就确定了,不会造成迷惑)。如:
1class Test { 2static { 3a = 3; 4// int b=a;//Cannot reference a field before it is defined 5// System.out.println(a);//Cannot reference a field before it is defined 6b = 3; 7 } 8staticinta = 1; 9staticint b;1011publicstaticvoid main(String[] args) {12System.out.println(a);//113System.out.println(b);//314 }15}
判断方法:
显示初始化内部隐含 定义变量和对变量进行赋值的初始化块两部分,所以初始化块和显示初始化哪个在后变量的最终值就是该值。
更多示例:
1:
1class C { 2 3static { 4a = 2; 5b = 2; 6 } 7staticint a; 8staticintb = 1; 910public C() {11e = 3;12 }1314 {15c = 2;16d = 2;17e = 2;18 }19int c;20intd = 1;21inte = 1;2223publicstaticvoid main(String[] args) {24 System.out.println(C.a);//225 System.out.println(C.b);//126System.out.println(new C().c);//227System.out.println(new C().d);//128System.out.println(new C().e);//329}
2:
1class C { 2public C() { 3 } 4 5 { 6a = 3; 7 } 8static { 9a = 2;10 }11staticint a;12staticint b;1314publicstaticvoid main(String[] args) {15System.out.println(C.a);// 216System.out.println(newC().a);// 317System.out.println(C.b);// 018 }19}
3:
1class C { 2// 以下关于静态初始化的 3static { 4a = 2; 5 } 6staticinta = 1; 7staticintb = 1; 8static { 9b = 2;10c = 2;11 }12staticint c;1314 {15d = 2;16 }17intd = 1;18inte = 1;19 {20e = 2;21f = 2;22 }23int f;2425publicstaticvoid main(String[] args) {26System.out.println(C.a);// 127System.out.println(C.b);// 228System.out.println(newC().c);// 229System.out.println(newC().d);// 130System.out.println(newC().e);// 231System.out.println(newC().f);// 232 }33}
3、总结
执行顺序:
1、类内容(静态变量、静态初始化块) => 实例内容(变量、初始化块、构造器)
2、父类的(静态变量、静态初始化块)=> 子类的(静态变量、静态初始化块)=> 父类的(变量、初始化块、构造器)=> 子类的(变量、初始化块、构造器)
初始化块可以对在它之后定义的变量赋值,但不能访问(如打印)。
变量最终值:一个变量,若显示初始化、初始化块对该变量赋值、构造方法对该变量赋值同时存在,则变量最终值如何确定:
1、按执行顺序
2、若对变量赋值的初始化块在变量定义前时:若变量显示初始化了则最终为显示初始化值,否则为初始化块的赋值。