Java对象初始化过程代码块和构造器的调用顺序

目录
  • 前言
    • 代码加载的优先级顺序
    • 构造方法的执行顺序
  • 各种代码块的定义
    • 静态代码块
    • 有关静态代码块再详细介绍下
    • 局部代码块
  • 验证各代码块的执行顺序
  • 验证存在继承关系中各代码块的执行顺序
  • 通过字节码深究实例代码块优先于构造器原因

前言

对Java对象初始化过程 代码块与构造器调用顺序进行整理说明。先说结论具体论证在下文。

代码加载的优先级顺序

静态代码块、静态成员变量->非静态代码块、非静态成员变量->new其他对象调用对应对象构造方法(在本地对象的方法外包括构造方法)->new本地对象调用构造方法。

注意:若new对象时,该对象中有静态代码块和非静态代码块,每new一次对象,非静态代码块都会执行一次,但静态代码块只会执行一次往后new对象都不会再执行。】

构造方法的执行顺序

父类静态代码块(静态变量 > 静态块) > 子类的静态代码块 > 父类构造代码块、构造方法> 子类的构造代码块、构造方法

各种代码块的定义

静态代码块

class Demo{ static { //静态代码块...... } }

特点:  1、Java静态代码块中的代码会在类加载JVM时运行,且只被执行一次 2、静态块常用来执行类属性的初始化 ,和一些全局初始化的工作 3、静态块优先于各种代码块以及构造函数,如果一个类中有多个静态代码块,会按照书写顺序依次执行 4、静态代码块可以定义在类的任何地方中除了方法体中【这里的方法体是任何方法体】 5、静态代码块不能访问普通变量

有关静态代码块再详细介绍下

静态代码块:在java中使用static关键字声明的代码块。静态块用于初始化类,为类的属性初始化。每个静态代码块只会执行一次。

由于JVM在加载类时会执行静态代码块,所以静态代码块先于主方法执行。 如果类中包含多个静态代码块,那么将按照"先定义的代码先执行,后定义的代码后执行"。 【注意:1 静态代码块不能存在于任何方法体内。2 静态代码块不能直接访问静态实例变量和实例方法,需要通过类的实例对象来访问。】 实例代码块 实例代码块 又叫 构造初始化块 , 构造代码块 , 初始化块 。

class Demo{ { //实例代码块...... } }

特点:

  • 1、构造代码块在创建对象时被调用,每次创建对象都会调用一次
  • 2、构造代码块优先于构造函数执行,同时构造代码块的运行依赖于构造函数
  • 3、构造代码块在类中定义

局部代码块

局部代码块又叫 普通代码块 , 方法代码块

class Demo{ public void test(){ { //局部代码块...... } } }

特点: 1、普通代码块定义在方法体中 2、普通代码块与实例代码块的格式一致都是{} 3、普通代码块与构造代码块唯一能直接看出的区别是构造代码块是在类中定义的,而普通代码块是在方法体中定义的 4、可以限定变量生命周期,及早释放,提高内存利用率

验证各代码块的执行顺序

举例代码如下:

class Init {
    public Init() {
        System.out.println("无参构造器");
    }
    public Init(int a) {
        System.out.println("有参构造器");
    }
    {
        System.out.println("实例代码块1");
    }
    {
        System.out.println("实例代码块2");
    }
    {
        System.out.println("实例代码块3");
    }
    static {
        System.out.println("静态初始化块1");
    }

    static {
        System.out.println("静态初始化块2");
    }

    public void method(){
    	{
    		System.out.println("普通初始化块");
    	}
    }
}

测试代码 如下:

class Demo {
    public static void main(String[] args) {
        Init init1 = new Init();
        init1.method();
        System.out.println("------------");
        Init init2 = new Init();
        init2.method();
        //多打印几个对象的目的是:方便看出Static静态代码块 是否只执行一次!!!
        System.out.println("------------");
        Init init3 = new Init();
        init3.method();
    }
}

运行结果如下图:

结论:

执行顺序为:静态代码块 > 实例代码块 > 构造函数 > 普通代码块,

且静态代码块,类加载的时候就会调用,且只调用一次(随着类的加载而执行)。

那么类什么时候会被加载呢?

- 创建对象实例时(new)
- 创建子类对象实例,父类也会被加载
- 使用类的静态成员时(静态属性,静态方法)

验证存在继承关系中各代码块的执行顺序

举例继承关系为 Three——> Two——> One,

代码如下:

class One {
    public One() {
        System.out.println("One构造器");
    }

    {
        System.out.println("One实例化块");
    }

    static {
        System.out.println("One静态代码块");

    }

}
class Two extends One {

    public Two() {
        System.out.println("Two构造器");
    }

    {
        System.out.println("Two实例化块");
    }

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

}

class Three extends Two {

    public Three() {
        System.out.println("Three构造器");
    }

    {
        System.out.println("Three实例化块");
    }
    static {
        System.out.println("Three静态代码块");
    }

}
//测试代码 如下:
public class Demo {
    public static void main(String[] args) {
        Three three = new Three();
        System.out.println("-----");
        Three three1 = new Three(); //重复执行的目的是为了 验证static是否只执行一次
        System.out.println("-----");
        Two three2 = new Three();   //验证 多态的情况下 用后面的类进行初始化 结果和上面一样
    }
}

根据执行结果可知,在多个类的继承中存在初始化块、静态初始化块、构造器,执行真实顺序为:先后执行父类A的静态块,父类B的静态块,最后子类的静态块,然后再执行父类A的实例代码块和构造器,然后是B类的实例代码块和构造器,最后执行子类C的实例代码块和构造器【注:这里的ABC对应One、Two、Three 】

结论:

多个类的继承中初始化块、静态初始化块、构造器的执行顺序为:

父类静态块——>子类静态块——>父类实例代码块——>父类构造器——>子类实例代码块——>子类构造器 ——>(如果有局部代码块, 再正常执行即可, 这里就没必要进行测试了)

通过字节码深究实例代码块优先于构造器原因

我们那一段代码作为例子说明下,代码如下:

class Init {
    public Init() {
        System.out.println("无参构造器");
    }
    public Init(int a) {
        System.out.println("有参构造器");

    }

    {
        System.out.println("实例代码块1");
    }

    {
        System.out.println("实例代码块2");
    }

    {
        System.out.println("实例代码块3");
    }

    static {
        System.out.println("静态初始化块1");
    }

    static {
        System.out.println("静态初始化块2");
    }

    public void method(){
        {
            System.out.println("普通初始化块");
        }
    }
}

接下来让我们看看 , Init.java编译完的的字节码文件(Init.class)

从这个字节码文件就可以很清晰的看出, 实例代码块实际上是被依次放到了构造方法的第一句, 所以可以的出此结论: 实例代码块的执行顺序是优先于构造器的。

到此这篇关于Java对象初始化过程代码块和构造器的调用顺序的文章就介绍到这了,更多相关Java对象初始化过内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Java——对象初始化顺序使用详解

    一. 代码块的概念 在探究对象初始化顺序之前,我们先通过代码来了解一下代码块的概念. class Test{ public static String str1; //静态字段 public String str2; //普通字段 static{ //静态代码块 } { //构造代码块 } public Test() { //构造函数 } } 二. 创建子类对象时,对象的初始化顺序 1. 字段初始化.代码块和构造函数的执行顺序 我们先看代码和结果 public class CodeBlockTe

  • java对象初始化顺序验证示例

    复制代码 代码如下: public class Derive extends Base {    private Member m1 = new Member("Member 1");    {        System.out.println("Initial Block()");    } public Derive() {        System.out.println("Derive()");    } private Member

  • 通过java字节码分析学习对象初始化顺序

    复制代码 代码如下: mockery.checking(new Expectations() { {               one(new Object()).toString();               will(returnValue(""));           }       }); 下面写一个写一个简单的类演示这个例子 复制代码 代码如下: public class Test { int i = 1;    {        int j = 1;       

  • java对象初始化代码详解

    本文主要记录JAVA中对象的初始化过程,包括实例变量的初始化和类变量的初始化以及final关键字对初始化的影响.另外,还讨论了由于继承原因,探讨了引用变量的编译时类型和运行时类型 一,实例变量的初始化 这里首先介绍下创建对象的过程: 类型为Dog的一个对象首次创建时,或者Dog类的static字段或static方法首次访问时,Java解释器必须找到Dog.class(在事先设定好的路径里面搜索):  找到Dog.class后(它会创建一个Class对象),它的所有static初始化模块都会运行.

  • 深入介绍Java对象初始化

    前言 在Java中,一个对象在可以被使用之前必须要被正确地初始化,这一点是Java规范规定的. 自动初始化(默认值) 一个类的所有基本数据成员都会得到初始化,运行下面的例子可以查看这些默认值: class Default{ boolean t; char c; byte b; short s; int i; long l; float f; double d; public void show() { System.out.println("基本类型 初始化值\n"+ "bo

  • Java对象初始化顺序的使用

    单一类:(静态成员变量&静态初始化块)<(成员变量&初始化块)<构造函数 复制代码 代码如下: public class 对象初始化顺序 {    public static void main(String[] args){        Person p = new Person();    }}class Person{    public static String staticfield ="静态成员变量";    public String fi

  • Java 超详细讲解对象的构造及初始化

    目录 如何初始化对象 构造方法 特性 默认初始化 就地初始化 如何初始化对象 我们知道再Java方法内部定义一个局部变量的时候,必须要初始化,否则就会编译失败 要让这串代码通过编译,很简单,只需要在正式使用a之前,给a设置一个初始值就好那么对于创造好的对象来说,我们也要进行相对应的初始化我们先写一个Mydate的类 public class MyDate { public int year; public int month; public int day; /** * 设置日期: */ pub

  • java中的this引用及对象构造初始化

    目录 1. this 引用 1.1 为什么要有this引用 1.2 什么是this引用 1.3 this引用的特性 1.4 this引用练习题 2. 对象的构造及初始化 2.1 如何初始化对象 2.2 构造方法 2.2.1 概念 2.2.2 特性 2.3 默认初始化 2.4 就地初始化 1. this 引用 1.1 为什么要有this引用 先来写一个日期类的例子: public class classCode { public int year; public int month; public

  • Java中对象初始化顺序的详细介绍

    前言 在Java中,一个对象在可以被使用之前必须要被正确地初始化,这一点是Java规范规定的.最近我发现了一个有趣的问题,这个问题的答案乍一看下骗过了我的眼睛.看一下这三个类: package com.ds.test; public class Upper { String upperString; public Upper() { Initializer.initialize(this); } } package com.ds.test; public class Lower extends

  • Java对象初始化过程代码块和构造器的调用顺序

    目录 前言 代码加载的优先级顺序 构造方法的执行顺序 各种代码块的定义 静态代码块 有关静态代码块再详细介绍下 局部代码块 验证各代码块的执行顺序 验证存在继承关系中各代码块的执行顺序 通过字节码深究实例代码块优先于构造器原因 前言 对Java对象初始化过程 代码块与构造器调用顺序进行整理说明.先说结论具体论证在下文. 代码加载的优先级顺序 静态代码块.静态成员变量->非静态代码块.非静态成员变量->new其他对象调用对应对象构造方法(在本地对象的方法外包括构造方法)->new本地对象调

  • java中的静态代码块、构造代码块、构造方法详解

    运行下面这段代码,观察其结果: package com.test; public class HelloB extends HelloA { public HelloB() { } { System.out.println("I'm B class"); } static { System.out.println("static B"); } public static void main(String[] args) { new HelloB(); } } cla

  • java 对象实例化过程中的多态特性解析

    目录 java 对象实例化过程中的多态特性 通过案例说明 通过上述代码 java对象的三个特性(封装.继承.多态) 1.封装 2.继承 3.多态 java 对象实例化过程中的多态特性 执行对象实例化过程中遵循多态特性 ==> 调用的方法都是实例化的子类中的重写方法,只有明确调用了super.xxx关键词或者是子类中没有该方法时,才会去调用父类相同的同名方法. 通过案例说明 package com.njau.test1; class Test { public static void main(S

  • Java对象流实例代码

    将日期对象和向量对象写入文件,然后从文件中读出并输出到屏幕上 package objstream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io

  • java中静态代码块与构造方法的执行顺序判断

    前言 静态代码优先于非静态的代码,是因为被static修饰的成员都是类成员,会随着JVM加载类的时候加载而执行,而没有被static修饰的成员也被称为实例成员,需要创建对象才会随之加载到堆内存.所以静态的会优先非静态的. 执行构造器(构造方法)的时候,在执行方法体之前存在隐式三步: 1,super语句,可能出现以下三种情况: 1)构造方法体的第一行是this语句,则不会执行隐式三步, 2)构造方法体的第一行是super语句,则调用相应的父类的构造方法, 3)构造方法体的第一行既不是this语句也

  • Java 多线程的同步代码块详解

    目录 synchronized 同步代码块 同步方法(this锁) 静态同步方法 死锁问题 lock 总结 火车站抢票问题 由于现实中买票也不会是零延迟的,为了真实性加入了延迟机制,也就是线程休眠语句 package test.MyThread.ticketDemo; public class RunnableThread implements Runnable{ private int ticket = 100; @Override public void run(){ while(true)

随机推荐