文档章节

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

镜子哥哥
 镜子哥哥
发布于 2016/11/19 15:53
字数 1042
阅读 5
收藏 0

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

  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()方法-->父类的普通成员变量和方法-->父类的构造方法->该类的普通成员变量和方法-->该类的构造方法-->结束

© 著作权归作者所有

共有 人打赏支持
镜子哥哥
粉丝 1
博文 19
码字总数 14425
作品 0
广州
编写高质量代码:改善Java程序的151个建议 --[98~105]

建议的采用顺序是List中泛型顺序依次为T、?、Object (1)、List是确定的某一个类型   List表示的是List集合中的元素都为T类型,具体类型在运行期决定;List<?>表示的是任意类型,与List类似...

西北野狼
08/13
0
0
干货——详解Java中的关键字

在平时编码中,我们可能只注意了这些static,final,volatile等关键字的使用,忽略了他们的细节,更深层次的意义。 本文总结了Java中所有常见的关键字以及一些例子。 static 关键字 概述: ...

Janti
07/22
0
0
java变量,初始化快,构造函数的执行顺序

对于JAVA中类的初始化是一个很基础的问题,其中的一些问题也是易被学习者所忽略。当在编写代码的时候碰到时,常被这些问题引发的错误,感觉莫名其妙。而且现在许多大公司的面试题,对于这方面...

清风傲剑
2014/08/19
0
0
Java 走向C++

本文不涉及一些微妙蛋疼的语法比较, 关注的是宏观方面, 当然后期逐步更新如果, 如果觉得必要, 可能会加上. 议题之一: 初始化的比较 1. CPP基类的任何类构造函数会默认调用父类的不带参数的构...

晨曦之光
2012/03/09
31
0
Java 走向C++

本文不涉及一些微妙蛋疼的语法比较, 关注的是宏观方面, 当然后期逐步更新如果, 如果觉得必要, 可能会加上. 议题之一: 初始化的比较 1. CPP基类的任何类构造函数会默认调用父类的不带参数的构...

晨曦之光
2012/03/09
81
0

没有更多内容

加载失败,请刷新页面

加载更多

ppwjs之bootstrap文字排版:字体大小写设置

<!DOCTYPT html><html><head><meta http-equiv="content-type" content="text/html; charset=utf-8" /><title>ppwjs欢迎您</title><link rel="icon" href="/favicon.ico" ......

ppwjs
15分钟前
0
0
线性代数入门

线性代数的概念对于理解机器学习背后的原理非常重要,尤其是在深度学习领域中。它可以帮助我们更好地理解算法内部到底是怎么运行的,借此,我们就能够更好的做出决策。所以,如果你真的希望了...

牛奋Debug
29分钟前
0
0
开发5分钟,调试2小时 - 该如何debug?

几年来我在答疑群、论坛、公众号、知乎回答的各种问题,没有一万也有八千。其中有三分之二以上都是在帮人看报错,帮人 debug(调试代码)。 可以说,会不会 debug,有没有 debug 的意识,懂不...

crossin
30分钟前
0
1
SQL count(*) 和count(1)的区别

开发中经常会使用这两个聚合函数,作用都是用来统计记录行,今天查找资料发现,其实这两个函数并没有区别, 实践才是检验的标准,首先看执行计划(表是我自己建立的): 可以看到,两个执行计...

一曲图森破
34分钟前
1
0
区块链100讲:详解区块链之P2P网络

1 P2P网络 如果我们简单来看 P2P 技术,它的应用领域已经非常广泛了,从流媒体到点对点通讯、从文件共享到协同处理,多种领域都有它的身影出现。 同样的,P2P 的网络协议也有很多,比较常见的...

HiBlock
52分钟前
0
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部