Java类静态属性、静态块、非静态属性、非静态块、构造函数在初始化时的执行顺序

前言

今天在看Android ContentProvider实现的时候,突然想到了Java类在new的过程中,静态域、静态块、非静态域、非静态块、构造函数的执行顺序问题。其实这是一个很经典的问题,非常考察对Java基础知识的掌握程度。很多面试过程中相信也有这样的问题,趁着周末有时间复习一下。

结论

这里先把整理好的结论抛给大家,然后我在写个程序来验证我们的结论。在Java类被new的过程中,执行顺序如下:

  1. 实现自身的静态属性和静态代码块。(根据代码出现的顺序决定谁先执行)
  2. 实现自身的非静态属性和非静态代码块。
  3. 执行自身的构造函数。

在实现继承的类被new的过程中,初始化执行顺序如下:

  1. 实现父类的公共静态属性和静态块级代码。
  2. 实现自身的静态属性和静态块级代码。
  3. 实现父类的非静态属性和非静态代码块。
  4. 执行父类的构造函数。
  5. 实现自身的非静态属性和非静态代码块。
  6. 执行自身的构造函数。

这里需要简单的介绍一下静态代码块和非静态代码块。

1. 静态代码块:

static {
}

2. 非静态代码块

{
}

静态代码块和非静态代码块的异同点如下:

  • 相同点:都是JVM加载类时且在构造函数执行之前执行,在类中都可以定义多个,一般在代码块中对一些static变量进行赋值。
  • 不同点:静态代码块在非静态代码块之前执行(静态代码块 > 非静态代码块)。静态代码块只在第一次new时执行一次,之后不再执行。而非静态代码块每new一次就执行一次。

验证

对于结论的最好验证就是写出代码来进行结果证明。首先,来看一下无继承的类初始化时的执行顺序,代码如下:

public class InitOderTest {
	public static String STATIC_FIELD = "静态属性";

	// 静态块
	static {
		System.out.println(STATIC_FIELD);
		System.out.println("静态代码块");
	}

	public String field = "非静态属性";

	// 非静态块
	{
		System.out.println(field);
		System.out.println("非静态代码块");
	}

	public InitOderTest() {
		System.out.println("无参构造函数");
	}

	public static void main(String[] args) {
		InitOderTest test = new InitOderTest();
	}
}

执行结果:

静态属性
静态代码块
非静态属性
非静态代码块
无参构造函数

接下来,我们验证一下,当Java类实现继承后,执行顺序是否和我们的结论吻合。测试代码如下:

class ParentTest {
	public static String PARENT_STATIC_FIELD = "父类-静态属性";

	// 父类-静态块
	static {
		System.out.println(PARENT_STATIC_FIELD);
		System.out.println("父类-静态代码块");
	}

	public static String parentField = "父类-非静态属性";

	// 父类-非静态块
	{
		System.out.println(parentField);
		System.out.println("父类-非静态代码块");
	}

	public ParentTest() {
		System.out.println("父类—无参构造函数");
	}
}

public class InitOderTest extends ParentTest {
	public static String STATIC_FIELD = "静态属性";

	// 静态块
	static {
		System.out.println(STATIC_FIELD);
		System.out.println("静态代码块");
	}

	public String field = "非静态属性";

	// 非静态块
	{
		System.out.println(field);
		System.out.println("非静态代码块");
	}

	public InitOderTest() {
		System.out.println("无参构造函数");
	}

	public static void main(String[] args) {
		InitOderTest test = new InitOderTest();
	}
}

执行结果如下:

父类-静态属性
父类-静态代码块
静态属性
静态代码块
父类-非静态属性
父类-非静态代码块
父类—无参构造函数
非静态属性
非静态代码块
无参构造函数

通过程序验证,可以看出我们的结论是准确的。

时间: 2024-10-12 22:40:42

Java类静态属性、静态块、非静态属性、非静态块、构造函数在初始化时的执行顺序的相关文章

子父类中码静态代块 构造代码块. 代码块 构造函数 成员变量 实例变量 执行顺序

刚开始接触时,很不容易分清楚 创建子类或者多态的情况: /* 创建子类的情况: 1.父类静态代码块 2.子类静态代码块 3.父类构造块 /实例变量(new 创建的变量成员)//谁在前执行谁,执行完再执行构造函数 4.父类构造函数//父类构造函数有方法,如果方法子类有就执行子类的方法,没有才再执行父类方法.//如果子类有父类没有会报错!//父类私有该方法就执行父类的方法 5.子类构造块/实例变量//谁在前执行谁,执行完再执行构造函数 6.子类构造函数 7.子类普通方法//调用成员变量,看子类的值,

域初始化、静态块及构造方法等在创建类实例时的执行顺序(转载)

在<Core java 2: volumn 1, Edition 5>一书的第四章“对象与类”中讲到域赋值语句.实例块.静态块及构造方法等在创建类实例时的执行顺序,中文译本有些处翻译的不贴切,而英文原书中也有一处错误.本文通过一个小程序来说明类实例构造过程中的语句执行顺序. 程序如下: public class Teststaticblock { public Teststaticblock() { this("second"); System.out.println(&q

Java子类继承父类,当实例化子类对象时的执行顺序

子类继承父类,当实例化子类对象时,执行顺序如下:     父类层级静态块      自身静态块     父类块      父类构造器     自身块      自身构造器 由于继承,肯定应该先加载父类再加载子类,加载类自然会调用静态块,然后是调用父类的构造函数和子类的构造函数,不过构造函数调用前肯定要先调用域或块,这样才能正确创建对象. ················································赋值顺序如下:     父类的静态变量赋值     自身的静态变

java类静态域、块,非静态域、块,构造函数的初始化顺序

原文:http://ini.iteye.com/blog/2007835 面试的时候,经常会遇到这样的考题:给你两个类的代码,它们之间是继承的关系,每个类里只有构造器方法和一些变量, 构造器里可能还有一段代码对变量值进行了某种运算,另外还有一些将变量值输出到控制台的代码,然后让我们判断输出的结果.这实际上是在考查我们对于继承情况下类的初始化顺序的了解. 我们大家都知道,对于静态变量.静态初始化块.变量.初始化块.构造器,它们的初始化顺序以此是 (静态变量.静态初始化块)>(变量.初始化块)>构

请运行TestStaticInitializeBlock.java示例,观察输出结果,总结出“静态初始化块的执行顺序”。

class Root{ static{ System.out.println("Root的静态初始化块"); } { System.out.println("Root的普通初始化块"); } public Root() { System.out.println("Root的无参数的构造器"); }}class Mid extends Root{ static{ System.out.println("Mid的静态初始化块");

java中静态代码块、构造代码块、构造方法、main函数的执行顺序?

静态代码块:在类被加载的时候就运行了,且只运行一次.static{} 构造代码块:在创建对象时被调用,每次创建对象都会调用一次.比静态代码块少了static.{} 构造方法:用于创建对象时定义初始化的状态.构造函数不能直接调用,必须通过new运算符在创建对象时才会自动调用,一般方法是在程序执行到它的时候被调用. 先不创建对象,如下: public class Test { // 静态代码块 static { System.out.println("静态代码块"); } // 构造代码块

java类的初始化块/执行顺序,实例化对象数据赋值

java里初始化一个类的对象,通过初始化快或者构造方法进行数据赋值.与其相关的执行代码有这么几种: 静态初始化块 初始化块 构造方法 静态初始化块 静态初始化块只在类加载时执行一次,同时静态初始化块只能给静态变量赋值,不能初始化普通的成员变量. 非静态初始化块 非静态初始化块在每次初始化实例对象的时候都执行一次,可以给任意变量赋值. 构造方法 在每次初始化实例对象时调用. 重点:执行顺序-> 在加载类时执行一次静态初始化块(之后不再调用). 在每次初始化实例对象时:先执行非静态初始化块,再执行构

Java类的装载过程和静态代码块

在Java中,类装载器把一个类装入Java虚拟机中,要经过三个步骤来完成:装载.连接和初始化,其中连接又可以分成校验.准备和解析三步,除了解析外,其它步骤是严格按照顺序完成的,各个步骤的主要工作如下:1.装载2.连接3.初始化 一.装载阶段 装载阶段由三个基本动作组成1.通过类型的完全限定名,产生一个代表该类型的二进制数据流2.解析这个二进制数据流为方法区内的内部数据结3.构创建一个表示该类型的java.lang.Class类的实例 另外如果一个类装载器在预先装载的时遇到缺失或错误的class文

Java Object 构造方法的执行顺序

Java Object 构造方法的执行顺序 @author ixenos 为了使用类而做的准备工作包括三个步骤 1)加载:类加载器查找字节码(一般在classpath中找),从字节码创建一个Class对象 2)链接:验证字节码,为静态域(只是static修饰的域,不包含static final )分配存储空间,解析此类对其他类的所有引用 3)初始化:若该类有超类,对其初始化,执行静态初始化器(构造器算一个)和静态初始化块. 类初始化时构造方法执行顺序 对于某一个子类时: (1)初始化对象的存储空