必要知识:
1:在代码执行过程中会首先找到main方法,看main方法所在的类有没有父类,若有,则先加载父类,再加载子类。
2:静态方法的初始化,静态代码块的执行,静态方法的声明都是在类加载过程中完成的。
3:父类的加载都在出现在子类之前。
4:类的加载只有在需要这个类的时候才会加载。
5:在加载过程中会出现暂停类加载的现象。
6:父类无参构造和构造块是在子类实例化是最先执行的。
具体顺序
1、为所有的属性赋默认值。
2、父类静态属性的初始化,静态代码块的执行,静态方法的声明(按照顺序进行)。
3、子类静态属性的初始化,静态代码块的执行,静态方法的声明(按照顺序进行)。
4、父类非静态变量的初始化,非静态方法的声明,非静态代码块的执行(按照顺寻执行)。
5、父类的构造方法
6、子类非静态变量的初始化,非静态方法的声明,非静态代码块的执行(按照顺寻执行)。
7、子类的构造方法。(第4到第六在实例化类的时候才会执行)
举例(阿里巴巴面试题)
public class T extends father{
public static int k = 0;
public static T t0;
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");
{
print("构造块");
}
static {
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) {
}
}
class father{
static {
System.out.println("父类的静态构造块");
}
public father(){
System.out.println("父类的构造函数");//子类会默认调用父类的无参构造
}
public father(String a){
System.out.println("父类重载的构造方法");
}
{
System.out.println("父类的构造块");
}
}
执行过程:
1、先是找到main方法;然后加载父类,为父类的所有成员变量赋初值0.
输出:“父类的静态构造块”
2、父类加载完毕,加载子类。同样赋初值0.然后执行它遇到的第一个static。但是在为其初始化过程中遇到了对象的实例化,所以要暂停加载,先实例化。
3、然后实例化子类,先调用父类的无参构造。而父类会把构造代码块放到每个构造函数的最前面。所以会先执行父类的构造块,然后父类的构造函数(构造函数只有在调用时才会执行)。所以,会先输出“父类构造块”再输出“父类构造函数”而“父类重载的构造方法不会执行”因为没有人调用它。
4、执行完父类的构造函数后会执行子类的非静态变量的初始化,非静态方法的声明,构造块的执行。
所以会执行print(“j”)。因为类没有加载完,所以静态变量现在还是0.输出结果:“1:j
i=0,n=0”。执行构造块,输出“2:构造块 i=1 n=1”。执行构造函数输出:“3:t1 i=2 n=2”
5、实例化t2,重复第三步和第四步。输出:
“父类的构造块
父类的构造函数
4:j i=3 n=3
5:构造块 i=4 n=4
6:t2 i=5 n=5”
6、静态变量t1和t2初始化完成,继续加载初始化i.输出:“7:i i=6 n=6”并返回i=7.
7、初始化n=99.
8、执行静态块。输出“8:静态块 i=7 n=99”
-------------------------------------------------------daima
额外的知识:
每一个类的构造函数第一行代码都会调用一个的构造方法。要么是父类的,要么是自己的。如果不显示的调用,就默认是super()。这样做的好处是帮助初始化一些局部变量。
例子:
public class superTest1 {
int a;
//如果不自定义构造函数,就会有一个默认的无参构造(虽然没有用)
//但是一旦自定义了构造函数,默认的无参构造就没有了。
public superTest1(int a) {
this.a=a;
}
}
class superTest2 extends superTest1{
int b;
public superTest2(int a,int b) {
//这个地方不是this(...)就是super(.....).否则就调用super().这样就要保证父类有无参构造
this(a);
}
public superTest2(int a) {
super(a);
System.out.println("构造函数");
}
public int print() {
System.out.println("实例化一次");
return 0;
}
}
但是,虽然调用了父类的构造函数,却没有创建父类对象。
构造块:
构造块是在调用构造函数的时候执行,先于构造函数。可以在这里面初始化一些每个对象都一样的成员变量。无论调用什么构造函数,调用哪里的构造函数,它都会被执行。