JAVA中静态变量,静态代码块,静态初始化,非静态初始化的加载顺序
例题1
public class Test08 {
public static void main(String[] args) {
Zi zi = new Zi();
}
}
class Fu{
private static int i = getNum("(1)i");
private int j = getNum("(2)j");
static{
print("(3)父类静态代码块");
}
{
print("(4)父类非静态代码块,又称为构造代码块");
}
Fu(){
print("(5)父类构造器");
}
public static void print(String str){
System.out.println(str + "->" + i);
}
public static int getNum(String str){
print(str);
return ++i;
}
}
class Zi extends Fu{
private static int k = getNum("(6)k");
private int h = getNum("(7)h");
static{
print("(8)子类静态代码块");
}
{
print("(9)子类非静态代码块,又称为构造代码块");
}
Zi(){
print("(10)子类构造器");
}
public static void print(String str){
System.out.println(str + "->" + k);
}
public static int getNum(String str){
print(str);
return ++k;
}
}
a.构造代码块: {}
优先于构造方法执行,每new一次就会执行一次
b.静态代码块: static{}
优先于构造代码块和构造方法执行的,只执行一次
例题2
public class T {
public static int k = 0;
public static T t1 = new T("t1");
public static T t2 = new T("t2");
public static int i = print("i");
public static int n = 99;
public int j = print("j");
static{
print("静态块");
}
{
print("构造块");
}
public T(String str){
System.out.println((++k) + ":" + str + " i=" + i + " n=" + n);
++n;
++i;
}
public static int print(String str){
System.out.println((++k) + ":" + str + " i=" + i + " n=" + n);
++n;
return ++i;
}
public static void main(String[] args) {
}
}
首先看到static关键字,脑子里面第一反应有几点,
1、公有属性,可以有类名称直接访问。
2、静态方法,可以有类名称直接方法。
3、静态方法或者属性,可以再对象实例化之前就调用
至于该题中,顺序执行,先执行public static int k =0 ;
因为没有输出不用考虑这个,接着public static Text t1 = new Text("t1") ;
在t1对象初始化时先执行非静态方法或者非静态常量,顺序执行,接着运行构造参数,
根据程序来看应该打印三条记录,分别是
1:j i=0 n=02:构造块 i=1 n=13:t1 i=2 n=2
接下来public static Text t2 = new Text("t2") ;同理,执行完之后继续执行static代码块或者赋值静态变量,在main()方法中new了一个新的实例,静态变量只执行一次,接下来就是顺序执行非静态方法---->构造方法。
几大原则
一、静态成员变量(Static)
- 静态成员变量为类变量,所有对象共享同一内存空间
- 静态成员变量的声明和定义仅在首次加载类的时候执行一次
- 首次加载类时首先对所有静态成员变量根据类型默认赋初值,然后再对有右值的赋右值
二、静态初始块
- 静态初始化块仅在首次加载类的时候执行一次
- 多个静态成员变量与静态初始化块 按照编写顺序先后执行
三、动态成员变量
- 动态成员变量定义在每次实例化对象时在构造函数之前执行
四、动态初始化块
-
动态初始化块在每次实例化对象时在构造函数之前执行
-
······多个动态成员变量与动态初始化块参照出现顺序先后执行······
总结:总的来说,在不涉及继承的前提下,当首次加载类时,按照如下顺序执行
-
按照出现顺序先后执行静态成员变量定义与静态初始化块
-
按照出现顺序先后执行动态成员变量定义与动态初始化块
-
执行构造函数
-
再次实例化对象时只执行第2、3步即可
-
············成员变量与定义与初始化块先于构造函数执行·········
五、当涉及到继承时,按照如下顺序执行
-
1、执行父类的静态成员变量定义与静态初始化块,执行子类的静态成员变量定义与静态初始化块
-
2、执行父类的非静态成员变量定义与动态初始化块,执行父类构造方法
-
3、执行子类的非静态成员变量定义与动态初始化块,执行子类构造方法
-
另:父类构造方法中用到的方法如果已被子类重写,那么在构造子类对象时在调用父类构造函数中使用子类重写的方法