存在继承时,Static与Constructor加载顺序

#类的加载过程 类的生命周期

  1. 装载:查找和导入Class文件;

  2. 链接:把类的二进制数据合并到JRE中;

    • 校验:检查载入Class文件数据的正确性;

    • 准备:给类的静态变量分配存储空间;

    • 解析:将符号引用转成直接引用;

  3. 初始化:对类的静态变量,静态代码块执行初始化操作

#类初始化

  1. 遇到new、getstatic、putstatic或invokestatic这4条字节码指令时,如果类没有进行过初始化,则需要先触发其初始化。生成这4条指令的最常见的Java代码场景是:使用new关键字实例化对象的时候,读取或设置一个类的静态字段(被final修饰、已在编译期把结果放入常量池的静态字段除外)的时候,以及调用一个类的静态方法的时候。

  2. 使用java.lang.reflect包的方法对类进行反射调用的时候,如果类没有进行过初始化,则需要先触发其初始化。

  3. 当初始化一个类的时候,如果发现其父类还没有进行过初始化,则需要先触发其父类的初始化。

  4. 当虚拟机启动时,用户需要指定一个要执行的主类(包含main()方法的那个类),虚拟机会先初始化这个主类。

#实例化与初始化

  • 实例化是初始化的其中一部分,初始化还包括类本身的加载,比如静态代码的执行和静态成员变量的初始化。
  • 实例化就是new一个新的对象到堆内存空间,但静态化的代码就是类本身拥有的内存空间,被所有new的实例对象共享。
  • 不管new多少对象,类的静态代码部分只执行一次,就是在初始化时。

#一个demo ###代码

class StaticInitParent {
    static int i = 1;
    static int j;
    static {
    	int i = 10;
    	System.out.println("父类静态代码块1, i = " + i + ", j = " + j);
    } 
    public StaticInitParent() {
    	System.out.println("父类构造函数");
    	{
    		System.out.println("父类构造代码块");
    	}
    }
    {
    	System.out.println("父类普通代码块");
    }
    static void print(){
    	System.out.println("父类静态方法  i = " + i + ", j = " + ++j);
    }
    static {
    	System.out.println("父类静态代码块2, j = " + j);
    }
}

public class StaticInit extends StaticInitParent{
	static {
	    i++;
	    System.out.println("子类静态代码块1, i = " + i + ", j = " + j);
	} 
	
	public StaticInit() {
	    System.out.println("子类构造函数");
	    {
	    	System.out.println("子类构造代码块");
	    }
	}
	
	{
	    System.out.println("子类普通代码块");
	}
	
	static void print(){
	    System.out.println("子类静态方法  i = " + i + ", j = " + ++j);
	}
	
	static {
	    System.out.println("子类静态代码块2, j = " + j);
	}
	
	public static void main(String[] args){
		System.out.println("=====");
		StaticInit.print();
		StaticInit sta = new StaticInit();
	}
}

###运行结果

父类静态代码块1, i = 10, j = 0
父类静态代码块2, j = 0
子类静态代码块1, i = 2, j = 0
子类静态代码块2, j = 0
 =====
子类静态方法  i = 2, j = 1
父类普通代码块
父类构造函数
父类构造代码块
子类普通代码块
子类构造函数
子类构造代码块

###分析

  1. 首先加载父类的static变量和方法,顺序 和代码顺序有关;
  • 静态代码块中的变量是内部有效的,这样能理解变量 i 的输出;
  1. 然后加载子类的static变量和方法,顺序同样与代码顺序有关;
  • 子类继承了父类静态变量i的值1,在执行i++后输出2;
  1. 执行main()方法;
  2. 根据代码顺序,执行子类的静态函数;
  3. 接下来开始实例化,加载父类的普通代码块;
  • 这里也可以看出并没有再次执行静态代码部分;
  1. 加载父类的构造函数(内部执行顺序与代码顺序有关);
  2. 加载子类的普通代码块;
  3. 加载子类的构造函数,实例化结束;

#结论 当该类有父类的时候,类的加载过程是:(以下内容均处于初始化阶段)

父类的static成员变量和方法-->该类的static变量和方法-->main()方法-->父类的普通成员变量和方法-->父类的构造方法->该类的普通成员变量和方法-->该类的构造方法-->结束

转载于:https://my.oschina.net/jingzigege/blog/790777

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值