-
2019-08-14 11:52:00
1、基本原理
同C语言一样,java中也是将花括号{...},包括起来的代码称为一个代码块。java中我们通常将static修饰的代码块,称为静态代码块,随类存在,仅在类初始化时执行一次,那么类在什么时候初始化,主要有以下六种:
1)创建类的实例,也就是new一个对象
2)访问某个类或接口的静态变量,或者对该静态变量赋值
3)调用类的静态方法
4)反射(Class.forName(“com.lyj.load”))
5)初始化一个类的子类(会首先初始化子类的父类)
6)JVM启动时标明的启动类,即文件名和类名相同的那个类 ;若无此修饰则称为非静态代码块,随对象存在,创建几个对象就执行几次。废话不多,请看如下代码:
package jvm_mode; public class CodeBlock { static { System.out.println("静态代码块被执行"); } { System.out.println("非静态代码块被执行"); } public void show() { System.out.println("类方法被执行"); } public static void main(String[] args) { // TODO Auto-generated method stub System.out.println("main方法被执行"); new CodeBlock().show(); new CodeBlock().show(); } }
执行结果如下:
静态代码块被执行
main方法被执行
非静态代码块被执行
无参构造方法被执行
类方法被执行
非静态代码块被执行
无参构造方法被执行
类方法被执行
初步分析:
由输出结果我们可以看见,最先被打印的是静态代码块的输出内容,这就说明在类初始化(JVM启动时标明的启动类)的时候是先执行了静态代码块的内容,随后执行main主方法。通过new调用了类中的无参数构造方法创建对象,有打印结果可知,非静态代码块优先于构造方法执行。当再次创建实例调用方法的时候只有方法被调用了,而静态代码块不再执行,因此,静态代码块的特点是在着类的初始化时执行,而且只执行一次!show方法就不解释了。
初步结论:
静态代码块:随类存在,类初始化时执行一次,貌似优先于main主方法执行
非静态代码块:随对象存在,创建几次对象就执行几次,且优先于构造方法执行
2、从继承中看代码块的执行顺序
请看如下代码:
package jvm_mode; public class CodeBlock extends CodeBlockParent{ static { System.out.println("本类静态代码块被执行"); } { System.out.println("本类非静态代码块被执行"); } CodeBlock(){ System.out.println("本类无参构造方法被执行"); } public void show() { System.out.println("本类类方法被执行"); } public static void main(String[] args) { // TODO Auto-generated method stub System.out.println("本类main方法被执行"); //new CodeBlockParent().show(); new CodeBlock().show(); //new CodeBlockChild().show(); //CodeBlockChild.static_func(); } } class CodeBlockParent{ public static int P_S_VAL =100; public int P_VAL =101; static { System.out.println("父类静态代码块被执行,P_S_VAL="+P_S_VAL); } { System.out.println("父类非静态代码块被执行,P_VAL="+P_VAL); } CodeBlockParent(){ System.out.println("父类无参构造方法被执行"); } public void show() { System.out.println("父类类方法被执行"); } } class CodeBlockChild extends CodeBlock{ static { System.out.println("子类静态代码块被执行"); } { System.out.println("子类非静态代码块被执行"); } CodeBlockChild(){ System.out.println("子类无参构造方法被执行"); } public void show() { System.out.println("子类类方法被执行"); } public static void static_func() { System.out.println("子类静态方法被执行"); } }
代码中创建一个父类CodeBlockParent和一个子类CodeBlockChild
2.1、main方法中创建一个父类CodeBlockParent对象
执行结果:
父类静态代码块被执行,P_S_VAL=100
本类静态代码块被执行
本类main方法被执行
父类非静态代码块被执行,P_VAL=101
父类无参构造方法被执行
父类类方法被执行程序在执行流程如下:
1、首先,程序在执行时,需要进行本类(main主类)的初始化即CodeBlock类,初始化时发现本类有继承的父类CodeBlockParent,所以先要对父类进行初始化[执行父类静态代码块],之后执行本类的初始化操作[执行本类的静态代码块],由父类中的静态成员变量可知P_S_VAL,在执行时静态代码块时已经先于此被初始化成100了,静态成员变量的值在类链接[准备阶段]被初始化成0.
2、次之,进入本类的main主方法执行
3、创建父类对象,执行父类的非静态代码块、构造方法、方法等,需要说明的是,父类中的成员变量P_VAL在执行非静态代码块时已经先于此被初始化成101了。
2.2、main方法中创建一个本类的CodeBlock对象
执行结果:
父类静态代码块被执行,P_S_VAL=100
本类静态代码块被执行
本类main方法被执行
父类非静态代码块被执行,P_VAL=101
父类无参构造方法被执行
本类非静态代码块被执行
本类无参构造方法被执行
本类类方法被执行
程序执行流程:
初始化、和进入main主方法同2.1小节一样,不同的是创建子类对象前先要隐式的创建一个父类对象[继承特性],因此先要执行父类的非静态代码块、构造方法。之后才轮到本类的一系列操作
2.3、main方法中创建一个子类的CodeBlockChild对象
执行结果:
父类静态代码块被执行,P_S_VAL=100
本类静态代码块被执行
本类main方法被执行
子类静态代码块被执行
父类非静态代码块被执行,P_VAL=101
父类无参构造方法被执行
本类非静态代码块被执行
本类无参构造方法被执行
子类非静态代码块被执行
子类无参构造方法被执行
子类类方法被执行程序执行流程:
首先,子类的初始化在代码中第一次被主动使用,用new创建对象仅仅是主动使用其中的一种,因此当主方法中调用new CodeBlockChild().show();时先进行一次子类的初始化操作[子类静态代码块],如果后面继续创建子类对象,该子类初始化不在执行。 创建在子类的对象时根据继承特性先隐式创建的子类的父类CodeBlock、父类的父类CodeBlockParent对象
2.4、main方法中调用CodeBlockChild静态方法
运行结果
父类静态代码块被执行,P_S_VAL=100
本类静态代码块被执行
本类main方法被执行
子类静态代码块被执行
子类静态方法被执行程序执行流程:程序调用子类的静态方法static_func,子类第一次被主动使用进行初始化操作,执行静态代码块,之后调用了静态方法
结论:
静态代码块:随类存在,类初始化[发生于第一次主动使用]时执行一次,优先于非静态代码执行,优先于本类main主方法执行
非静态代码块:随对象存在,创建几次对象就执行几次,优先于构造方法执行
具体类的初始化顺序:父类的静态字段——>父类静态代码块——>子类静态字段——>子类静态代码块——>
父类成员变量(非静态字段)——>父类非静态代码块——>父类构造器——>子类成员变量——>子类非静态代码块——>子类构造器
疑问:在静态代码块中不能访问成员变量,想想这是为什么?它是否与成员的初始化顺序有必然的联系?
答:初始化顺序仅仅是次要原因,根本原因是此时的成员还没有随对象被创建出来
3、应用场景看代码块
......
更多相关内容 -
java 静态成员变量、非静态成员变量、静态代码块、非静态代码块、构造方法 执行顺序
2022-03-14 17:29:14java 静态代码块、非静态代码块、构造方法 执行顺序1.静态(static)成员变量和静态代码块代码块
static修饰的成员都是类成员,会随着JVM加载类的时候加载而执行,而没有被static修饰的成员也被称为实例成员,需要创建对象才会随之加载到堆内存。所以静态的会优先非静态的。静态成员变量优先于静态代码块执行;
2.非静态代码块和非静态成员变量
非静态代码块和静态代码块都是在JVM加载类时且在构造方法执行之前执行,非静态代码块在类中都可以定义多个;非静态代码块是在类被实例化的时候执行。每被实例化一次,就会被执行一次;非静态成员变量优先于非静态代码块和构造方法执行;
3.构造方法
执行构造方法的时候,在执行方法体之前存在隐式三步:
1)构造方法体的第一行是this语句,则不会执行隐式三步,
2)构造方法体的第一行是super语句,则调用相应的父类的构造方法,
3)构造方法体的第一行既不是this语句也不是super语句,则隐式调用super(),即其父类的默认构造方法,这也是为什么一个父类通常要提供默认构造方法的原因;代码示例:
package com.dhcc.demo.springbootymldemo02.test; public class Teacher { private String name; private Integer age; public Teacher(String str) { System.out.println(str + "--成员变量Teacher初始化"); } } package com.dhcc.demo.springbootymldemo02.test; import java.sql.Timestamp; public class Person { private static Teacher teacher = new Teacher("静态"); private Teacher teacherOne = new Teacher("非静态"); private Integer no; private Integer age; private String name; static { Timestamp timestamp = new Timestamp(System.currentTimeMillis()); try { Thread.sleep(1000); System.out.println("------父类的静态代码块执行------" + timestamp); } catch (InterruptedException e) { e.printStackTrace(); } } { Timestamp timestamp = new Timestamp(System.currentTimeMillis()); try { Thread.sleep(1000); System.out.println("------父类的非静态代码块执行------" + timestamp); } catch (InterruptedException e) { e.printStackTrace(); } } Person() { Timestamp timestamp = new Timestamp(System.currentTimeMillis()); try { Thread.sleep(1000); System.out.println("------父类的构造方法执行------" + timestamp); } catch (InterruptedException e) { e.printStackTrace(); } } }
package com.dhcc.demo.springbootymldemo02.test; import java.sql.Timestamp; public class Student extends Person { private Integer sNo; private Integer classNO; static { Timestamp timestamp = new Timestamp(System.currentTimeMillis()); try { Thread.sleep(1000); System.out.println("------Student类的静态代码块执行------" + timestamp); } catch (InterruptedException e) { e.printStackTrace(); } } { Timestamp timestamp = new Timestamp(System.currentTimeMillis()); try { Thread.sleep(1000); System.out.println("------Student类的非静态代码块执行------" + timestamp); } catch (InterruptedException e) { e.printStackTrace(); } } public Student() { super(); Timestamp timestamp = new Timestamp(System.currentTimeMillis()); try { Thread.sleep(1000); System.out.println("------Student类的构造方法执行------" + timestamp); } catch (InterruptedException e) { e.printStackTrace(); } } }
package com.dhcc.demo.springbootymldemo02.test; public class Test { public static void main(String[] args) { new Student(); } }
静态--成员变量Teacher初始化 ------父类的静态代码块执行------2022-03-28 11:16:40.657 ------Student类的静态代码块执行------2022-03-28 11:16:41.661 非静态--成员变量Teacher初始化 ------父类的非静态代码块执行------2022-03-28 11:16:42.669 ------父类的构造方法执行------2022-03-28 11:16:43.679 ------Student类的非静态代码块执行------2022-03-28 11:16:44.682 ------Student类的构造方法执行------2022-03-28 11:16:45.689
-
java类中的代码块-静态代码块和非静态代码块
2022-02-11 18:30:10静态代码块和非静态代码块的描述 代码块的作用 在类或者对象执行代码块,初始化属性的时候,可以写逻辑。静态代码块,只能直接定义静态属性 代码块的执行顺序:由父及子,静态先行展开全文 -
Java中静态代码块,非静态代码块,构造函数的执行顺序
2020-09-01 09:25:32非静态代码块:是用来初始化类的实例信息,在创建对象的时候就会被执行,且每创建一个对象都会被执行一次。执行的时候如果有静态初始化块,先执行静态初始化块再执行非静态初始化块,非静态初始化块会在构造函数执行...静态代码块:是用来初始化类的信息,在类被加载的时候就会被执行,且只执行一次。执行优先级高于非静态的初始化块。
非静态代码块:是用来初始化类的实例信息,在创建对象的时候就会被执行,且每创建一个对象都会被执行一次。执行的时候如果有静态初始化块,先执行静态初始化块再执行非静态初始化块,非静态初始化块会在构造函数执行时,在构造函数主体代码执行之前被运行。
构造方法:是用来创建对象的。
一、同类中静态代码块,非静态代码块,构造方法的执行顺序
执行顺序:静态代码块>非静态代码块>构造方法
即:程序在执行时,首先执行静态代码块,且只执行一次。接下来再创建对象时(new),首先执行非静态代码块,再执行构造方法。
示例1:
代码:
package com.csu.marden; public class Demo { static{ System.out.println("static"); } { System.out.println("no static"); } Demo5(){ System.out.println("constructor"); } public static void main(String[] args) { } }
执行结果:
分析:
上述Demo类包含静态代码块,非静态代码块和构造方法。但是该类中没有具体的执行,只完成了类的加载,即只有静态代码块在类加载的时候被执行,且只执行一次。由于没有对类的实例化,所有非静态代码块和构造方法均未执行。
示例2:
代码:
package com.csu.marden; public class Demo5 { static{ System.out.println("static"); } { System.out.println("no static"); } Demo5(){ System.out.println("constructor"); } public static void main(String[] args) { Demo demo=new Demo(); } }
执行结果:
分析:
上述Demo类包含静态代码块,非静态代码块和构造方法。上述代码首先完成了类加载,即静态代码块执行,且仅执行一次。然后创建了该类的实例,首先执行了非静态代码块,然后执行了构造方法。
示例3:
代码:
package com.csu.marden; public class Demo5 { static{ System.out.println("static"); } { System.out.println("no static"); } Demo5(){ System.out.println("constructor"); } public static void main(String[] args) { Demo demo1=new Demo(); Demo demo2=new Demo(); } }
执行结果:
分析:
上述Demo类包含静态代码块,非静态代码块和构造方法。上述代码首先完成了类加载,即静态代码块执行,且仅执行一次。然后创建了该类的两个实例,首先执行了非静态代码块,然后执行了构造方法。并且非静态代码块和构造方法,在每次创建新的对象时,都会被执行一次。
二、父类和子类中静态代码块,非静态代码块,构造方法的执行顺序
在Java继承中,父类子类构造方法、静态代码块、非静态代码块的执行顺序:
父类静态代码块 > 子类静态代码块 > 父类非静态代码块 > 父类构造方法 > 子类非静态代码块 > 子类构造方法
示例1:
代码:
//父类 public class Parent { static String name = "hello"; { System.out.println("parent-no-block"); } static { System.out.println("parent-static"); } public Parent() { System.out.println("parent-constructor"); } } //子类 public class Child extends Parent { static String childName = "hello"; { System.out.println("child-no-static"); } static { System.out.println("child-static"); } public Child() { System.out.println("child-constructor"); } } //测试类 public class Demo { public static void main(String[] args) { new Child(); } }
执行结果:
分析:
Java继承体系中,若子类继承了父类,在创建子类的时候,首先会调用父类的构造方法和非静态代码块完成类实例的初始化,然后调用子类的构造方法和非静态代码块完成类实例的初始化(子类需要根据父类的构造方法生成)。
所以在执行时(创建子类对象时),首先加载父类,即执行父类的静态代码块,且只执行一次,然后加载子类,即执行子类的静态代码块,同样只执行一次。然后执行父类的非静态代码块和构造方法完成父类实例的初始化,最后执行子类的非静态代码块和构造方法完成子类实例的初始化。
示例2:
代码:
//父类 public class Parent { static String name = "hello"; { System.out.println("parent-no-block"); } static { System.out.println("parent-static"); } public Parent() { System.out.println("parent-constructor"); } } //子类 public class Child extends Parent { static String childName = "hello"; { System.out.println("child-no-static"); } static { System.out.println("child-static"); } public Child() { System.out.println("child-constructor"); } } //测试类 public class Demo { public static void main(String[] args) { new Child(); new Child(); } }
执行结果:
分析:
在执行时(创建子类对象时),首先加载父类,即执行父类的静态代码块,且只执行一次,然后加载子类,即执行子类的静态代码块,同样只执行一次。然后执行父类的非静态代码块和构造方法完成父类实例的初始化,最后执行子类的非静态代码块和构造方法完成子类实例的初始化。由于本例中创建了两个子类对象,所以执行两次父类非静态代码块和构造函数,子类非静态代码块和构造函数。
-
Java的静态代码块、非静态代码块、构造函数
2021-01-12 21:17:21Java的静态代码块、非静态代码块、构造函数的简单的java代码 -
静态代码块和非静态代码块什么时候执行?
2021-12-20 19:52:23静态代码块和非静态代码块什么时候执行? 静态代码块随着类的加载而加载,非静态代码块随着对象的加载而加载 所以静态代码块再调用类的时候执行。非静态代码块创建对象时或者通过反射获取其类信息的时候执行 ... -
静态代码块、非静态代码块、构造方法的执行顺序
2019-05-07 09:19:07总结: 在外部调用静态方法时,可以使用”类名.方法名”的方式,也可以使用”对象名.方法名”的方式。而实例方法只有后面这种方式。也就是说,调用静态方法可以无需创建对象。...static{}静态代码块与{}非静态... -
java静态代码块与非静态代码块.doc
2020-08-24 13:45:46测试函数 public class TestStaticCon { public ... System.out.println"父类的非静态代码块在执行a=" + a; } { a = 8; System.out.println"父类的非静态代码块在执行a=" + a; } public TestStaticCon) { this"a在 -
java静态代码块与非静态代码块比较
2018-10-23 00:20:45得出结论1:非静态代码块不会在调用方法与成员时执行. 结论2:非静态代码块在创建实例时执行 结论3:非静态代码块每次创建实例时执行,而静态代码块只执行一次 结论4:静态代码块优先非静态代码块优先... -
静态代码块和非静态代码块的区别
2018-06-02 16:19:34摘自原文小结:1、静态代码块是在类加载时自动执行的,非静态代码块在创建对象自动执行的代码,不创建对象不执行该类的非静态代码块。 顺序: 静态代码块--》非静态代码块--》类构造方法。2、在静态方法里面只能直接... -
Java-静态代码块、非静态代码块、静态方法,非静态方法
2019-09-04 19:33:12执行顺序:静态代码块--非静态代码块--默认构造方法--普通方法 使用地方:非静态代码块可在普通方法中定义(不过作用不大)。静态代码块必须在类中进行 使用场景:静态代码块可用来初始化一些项目最常用的变量或对象... -
完全理解Java中静态代码块,静态方法,静态变量,非静态代码块,非静态变量,构造函数初始化顺序
2019-06-30 22:12:211、静态代码块(静态初始化块,静态域): 使用static关键字和{}声明的代码块,格式如下: public class People{ static{ System.out.println("静态代码块"); } } 作用: 需要在项目启动时就执行的代码... -
静态代码块与非静态代码块的区别(Java)
2018-07-29 13:46:15静态代码块是以static修饰的代码块,反之没有用static修饰的代码块为非静态代码块,如下所示: 静态代码块: static{ 若干代码 } 非静态代码块: { 若干代码 } 它们之间的区别主要如下: 静态代码块在... -
java中静态和非静态代码块
2017-11-18 21:34:37java中经常有一些静态块,这是用来在生成类之前进行的...非静态语句代码块 } 异同点 相同点:都是在JVM加载类时且在构造方法执行之前执行,在类中都可以定义多个,一般在代码块中对一些static变量进行赋 值 -
Java子类与父类中静态代码块、非静态代码块、构造函数的执行顺序一览表
2018-11-02 15:44:42③父类非静态代码块>>④父类构造函数>>⑤子类非静态代码块>>⑥子类构造函数 大致总结: 父类早于子类,静态早于非静态,非静态早于构造函数。 1、验证代码 package ... -
[java]静态成员变量/静态代码块/非静态代码块执行顺序
2019-03-25 22:26:06先给出代码,大家可以先思考一下将会打印什么内容: public class StaticTest { public static void main(String[] args) { staticFunction(); System.out.println("main中b:"+b); } static StaticTest static... -
静态代码块和非静态代码块区别
2017-11-27 11:46:27静态代码块在第一次创建对象的时候执行...非静态代码块每创建一次对象就执行一次。class Cat{ Cat(){ System.out.println("构造代码块"); } static{ System.out.println("静态代码块"); } { System.out.println -
静态代码块、非静态代码块、构造函数三者执行顺序
2017-09-29 11:56:22主要探讨一下关于静态代码块,非静态代码块,构造函数的执行顺序。 如有错误,欢迎指出。首先: 静态成员变量和静态代码块的优先级是一样的,先定义的先执行。 在创建一个对象的时候会执行非静态代码块和构造函数... -
java中静态代码块,非静态代码块,构造函数之间的执行顺序
2016-03-15 16:05:33它们之间的执行顺序为:静态代码块—>非静态代码块—>构造方法。静态代码块只在第一次new执行一次,之后不再执行,而非静态代码块在每new一次就执行一次。非静态代码块可在普通方法中定义(不过作用不大);而静态代码... -
Java类中的静态属性、静态代码块块、非静态属性、非静态代码块块、构造函数在初始化时的执行顺序
2018-06-08 16:27:20序言 前几天在复习J2SE的时候,看到了这个Java类在new的过程中,静态域、静态块、非静态域、非静态块、构造函数的执行... 实现自身的静态属性和静态代码块。 注意:它们两个的执行顺序根据自身出现的顺序决定2... -
静态代码块 非静态代码块 构造函数 的执行顺序
2020-11-10 19:59:19public class Test { public Test() { ... //非静态代码块 { System.out.print("非静态代码块!--"); } //静态代码块 static { System.out.print("静态代码块!--"); } private static void test() { . -
java静态代码块、非静态代码块、构造器执行顺序
2015-11-23 11:47:42java静态代码块、非静态代码块、构造器执行顺序 1)有静态代码块,先执行父类静态代码块,再执行子类静态代码块;...2)有非静态代码块,先执行父类非静态代码块,父类构造器,再执行子类非静态代码块,子类构造器 -
Java中静态、非静态代码块, 无参、有参构造方法执行顺序
2018-03-28 01:11:091、静态代码块和非静态代码块: 相同点:都是JVM加载类时且在构造函数执行之前执行,在类中都可以定义多个,一般在代码块中对一些static变量进行赋值。 不同点:静态代码块在非静态代码块之前执行。静态代码块只... -
Java初始化块(静态代码块和非静态代码块)
2018-03-19 10:24:41 ...与构造器作用非常类似的是初始化块,它也可以对Java对象进行初始化操作。 初始化块  ... -
Java静态代码块与非静态代码块面试题
2018-06-06 15:53:09java静态代码块面试题 public class Father { static{ System.out.println("Father___的静态代码块&amp... -
Java中静态代码块、非静态代码块、构造函数的执行顺序与作用
2015-07-16 18:09:55一、观察一段源码与结果 public class StaticDemo { private static int i=1; static { System.out.println("static前代码块执行顺序...System.out.println("非static代码块执行顺序为"+i); i=i+1; } public StaticDem -
则父类B构造函数、父类B静态代码块、父类B非静态代码块、子类A构造函数、子类A静态代码块、子类A非静态...
2018-09-17 19:12:003,非静态代码块优于构造函数执行 所以执行顺序如下: 父类B静态代码块->子类A静态代码块->父类B非静态代码块->父类B构造函数->子类A非静态代码块->子类A构造函数 转载于:...