对象加载的流程总结

对象加载的流程

  1. 加载Demo.class文件进方法区,并进行空间分配。

  2. 如果有静态变量,先默认初始化,显示初始化。

  3. 如果有静态代码块,要执行,仅执行一次。

  4. main方法进栈,通过new在堆中开辟空间,并明确首地址。

  5. 对对象的属性进行默认初始化。

  6. 调用相应的构造函数进行初始化。

  7. 构造函数内部。
    7.1 调用父类的构造函数super()。
    7.2 成员变量的显示初始化。
    7.3 构造代码块初始化。
    7.4 构造函数内容自定义初始化。

  8. 对象初始化完毕,将地址赋值给引用变量。

代码实现

先对父类进行测试

public class father {

	@Override
	public String toString() {
		return "父亲的 [age=" + age + "]";
	}

	public int age = 18;

	public father() {
		System.out.println("父亲的构造方法");
	}

	static {
		System.out.println("父亲的static代码块");
	}
	{
		System.out.println("父亲构造代码块");
	}
}

测试代码

import com.Demo.StaticDemo;
import com.Demo.father;
import com.Demo.son;
import com.Demo.yeye;

public class statictest {
	public static void main(String[] args) {
		father f=new father();
		System.out.println(f);
		//StaticDemo.print();
		//son s=new son();
		//s.haha();
		//yeye y=new yeye();
		//System.out.println(y.age);
		//System.out.println(y.sex);
		//System.out.println(yeye.sex);
	}
}

测试结果
在这里插入图片描述

!!! 注意,静态代码块,构造代码块,和构造函数,他们的执行顺序和写的时候的顺序没关系,也就是说书写的顺序不影响这三个的执行顺序。

对子类和父类进行测验

package com.Demo;

public class son extends father {
	static {
		System.out.println("儿子的static代码块");
	}
	
	public  son() {
		super();
		System.out.println("儿子的构造方法");
	}
	public void haha() {
		System.out.println("年龄"+age);
	}
	{
		System.out.println("儿子构造代码块");
	}
	
}

测试代码

import com.Demo.StaticDemo;
import com.Demo.father;
import com.Demo.son;
import com.Demo.yeye;

public class statictest {
	public static void main(String[] args) {
		//father f=new father();
		//System.out.println(f);
		//StaticDemo.print();
		son s=new son();
		s.haha();
		//yeye y=new yeye();
		//System.out.println(y.age);
		//System.out.println(y.sex);
		//System.out.println(yeye.sex);
	}
}

测试结果

在这里插入图片描述

再来个复杂的我们看一下。

public class OOPDemoE {
	public static void main(String[] args) {
		Son son=new Son();
		son.show();
		son.test();
	}
}
class Father{
	int haha;
	Father(){
		haha=100;
		show();//调用的是子类的show 因为重写
	}
	void show(){
		System.out.println("Fatehr show"+haha);
	}
}
class Son extends Father{
	int xixi=50;
	Son(){
		super();//父类的构造函数一旦执行完毕 立马显式初始化
		show();
		test();
		xixi=200;
		show();
		test();
	}
	void show(){
		System.out.println("Son show"+haha+":"+xixi);
	}
	void test(){
		System.out.println("Son test"+haha+":"+xixi);
	}
}

思考一下它的执行顺序是什么?
在这里插入图片描述


补充:

JAVA初始化顺序:

1.初始化静态属性,即静态代码和静态变量。按照先父类再子类的顺序初始化。

2.初始化类属性,即成员变量、代码块和构造函数。其中类变量和代码块优先级相同且均优先于构造函数。也是按照先初始化父类再子类的顺序。

我们可以看到,类的初始化分为两大部分:即静态属性和非静态属性。静态属性优先于非静态属性。

优先级层次(相同优先级的属性按程序先后顺序初始化):

第一级:静态属性

    1. 父类:  静态成员变量=静态代码块

    2. 子类:  静态成员变量=静态代码块



第二级:非静态属性

    1. 父类:

        1.1  成员变量 = 代码块

        1.2  构造函数

    2. 子类:

        2.1  成员变量 = 代码块

        2.2  构造函数

package com.company;
class Father {
    public String str1 = getString("父类public变量");         //类变量
    public static String str2 = getString("父类静态变量");  //静态变量
    private String str3 = getString("父类private变量");        //类变量
    //类代码块
    {
        System.out.println("父类代码块");
    }
    //静态代码块
    static {
        System.out.println("父类静态代码块");
    }
    //father类构造函数
    Father() {
        System.out.println("父类构造函数");
    }
    //输出变量数值以作测试
    public static String getString(String i){
        System.out.println(i);
        return i;
    }
}
class Child extends Father{
    //father类构造函数
    Child() {
        System.out.println("Child类构造函数");
    }
    //类代码块
    {
        System.out.println("子类代码块");
    }
 
    //静态代码块
    static {
        System.out.println("子类静态代码块");
    }
    private String str6 = getString("子类private变量");   //类变量
    public static String str5 = getString("子类静态变量");  //静态变量
    public String str4 = getString("子类public变量");    //类变量
}
public class Demo {
    public static void main(String[] args) {
        new Child();
    }
}

测试结果:
在这里插入图片描述
结果分析:

在子类的代码中,我们故意将静态代码块、静态变量、成员变量,代码块和构造函数顺序调整。可以看到程序的执行结果始终严格按照上面所列的优先级执行。

/延伸*/

为什么会子类的静态代码出现在父类的非静态属性之前呢,这里涉及到Java的装载和实例化。

类的加载和实例化顺序:

1) 在堆内存中生成class对象, 把静态变量和静态方法加载到方法区, 这个堆内存中的class对象是方法区数据的入口

2) 静态变量默认初始化

3) 静态变量显式初始化

4) 执行静态代码块

5) 成员变量默认初始化, 显示初始化

6) 执行构造函数

其中有涉及父子关系的类的装载中,先父类静态变量和代码块初始化,再子类。然后实例化时,父类成员变量和代码块初始化, 执行父类构造函数, 子类成员变量和代码块初始化, 执行子类构造函数。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值