代码执行顺序。java笔记(四)

必要知识:
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;
	}
}

但是,虽然调用了父类的构造函数,却没有创建父类对象。

构造块:
构造块是在调用构造函数的时候执行,先于构造函数。可以在这里面初始化一些每个对象都一样的成员变量。无论调用什么构造函数,调用哪里的构造函数,它都会被执行。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值