java的static块执行时机

一、误区:简单认为JAVA静态代码块在类被加载时就会自动执行。证错如下:

[java] view plain copy

  1. class MyClass1 {
  2. static {//静态块
  3. System.out.println("static block ");
  4. }
  5. }
  6. public class Main {
  7. Class[] classArray = {
  8. MyClass1.class//这样引用该类,必然需要将该类加载到虚拟机中
  9. };
  10. public static void main(String[] args){
  11. System.out.println("hello word");
  12. }
  13. }

执行结果:并没有输出" static bolck"

二、正解:static块真正的执行时机。如果了解JVM原理,我们知道,一个类的运行分为以下步骤:

  1. 装载
  2. 连接
  3. 初始化

其中装载阶段又三个基本动作组成:

  1. 通过类型的完全限定名,产生一个代表该类型的二进制数据流
  2. 解析这个二进制数据流为方法区内的内部数据结
  3. 构创建一个表示该类型的java.lang.Class类的实例

另外如果一个类装载器在预先装载的时遇到缺失或错误的class文件,它需要等到程序首次主动使用该类时才报告错误。

连接阶段又分为三部分:

  1. 验证,确认类型符合Java语言的语义,检查各个类之间的二进制兼容性(比如final的类不用拥有子类等),另外还需要进行符号引用的验证。
  2. 准备,Java虚拟机为类变量分配内存,设置默认初始值。
  3. 解析(可选的) ,在类型的常量池中寻找类,接口,字段和方法的符号引用,把这些符号引用替换成直接引用的过程。

  当一个类被主动使用时,Java虚拟就会对其初始化,如下六种情况为主动使用:

  1. 当创建某个类的新实例时(如通过new或者反射,克隆,反序列化等)
  2. 当调用某个类的静态方法时
  3. 当使用某个类或接口的静态字段时
  4. 当调用Java API中的某些反射方法时,比如类Class中的方法,或者java.lang.reflect中的类的方法时
  5. 当初始化某个子类时
  6. 当虚拟机启动某个被标明为启动类的类(即包含main方法的那个类)

Java编译器会收集所有的类变量初始化语句和类型的静态初始化器,将这些放到一个特殊的方法中:clinit。

 
实际上,static块的执行发生在“初始化”的阶段。初始化阶段,jvm主要完成对静态变量的初始化,静态块执行等工作。

下面我们看看执行static块的几种情况:

1、第一次new A()的过程会打印"";因为这个过程包括了初始化

2、第一次Class.forName("A")的过程会打印"";因为这个过程相当于Class.forName("A",true,this.getClass().getClassLoader());

3、第一次Class.forName("A",false,this.getClass().getClassLoader())的过程则不会打印""。因为false指明了装载类的过程中,不进行初始化。不初始化则不会执行static块。

参考资料:《深入Java虚拟机》

时间: 2024-10-09 15:54:11

java的static块执行时机的相关文章

java的static块及相关内容

原文地址:http://blog.csdn.NET/lubiaopan/article/details/4802430     感谢原作者! static{}(即static块),会在类被加载的时候执行且仅会被执行一次,一般用来初始化静态变量和调用静态方法,下面我们详细的讨论一下该语句块的特性及应用. 一.在程序的一次执行过程中,static{}语句块中的内容只被执行一次,看下面的示例: 示例一 [java] view plaincopy class Test{ public static in

深入java虚拟机之类的静态代码块执行时机

public class Test {   public static void main(String[] args) throws ClassNotFoundException {     // System.out.println(Class.forName("java.lang.String").getClassLoader());     // System.out.println(Class.forName("java.lang.Object").get

java finally块执行时机分析

java里 finally 关键字通常与try catch块一起使用.用来在方法结束前或发生异常时做一些资源释放的操作.最近也看到网上有一些讨论try catch finally关键词执行的顺序的文章,并给出了finally块是在方法最后执行的. 这些观点普遍认为: 1)finally关键词是在程序return语句后返回上一级方法前执行的,其中返回值会保存在一个临时区域,待执行完finally块的部分后,在将临时区域的值返回. 2)若finally块里有返回值会替换掉程序中前面的try 或cat

Java中代码块执行顺序

代码块:在Java中,使用{}括起来的代码被称为代码块.根据其位置和声明的不同,可以分为 局部代码块:局部位置,用于限定变量的生命周期.构造代码块:在类中的成员位置,用{}括起来的代码.每次调用构造方法执行前,都会先执行构造代码块.作用:可以把多个构造方法中的共同代码放到一起,对对象进行初始化.静态代码块:在类中的成员位置,用{}括起来的代码,只不过它用static修饰了.作用:一般是对类进行初始化. 静态代码块,构造代码块,构造方法的执行顺序? 首先执行静态代码块 接着执行构造代码块 最后指向

静态代码块执行时机

静态变量在准备阶段赋默认零值,在初始化阶段赋用户值,静态代码块在初始化阶段执行 public class StaticBlockDemo { static int a = 2; static { // 如果在准备阶段,则a = 0; // 如果在初始化阶段, a = 2; System.out.println(a); } public static void main(String[] args) { } } 原文地址:https://www.cnblogs.com/heyboom/p/1140

【转】Java中finally的执行时机

原文链接 http://blog.csdn.net/imzoer/article/details/8037970 finally是在catch执行之后return之前执行的. 那么,如果在finally中改变了catch中要返回的对象,那么,返回值改变了吗? 看代码: 上面代码输出是3,说明finally中的改变对catch中的返回值产生了影响. 再看下面代码: 奇怪的是,上面的代码输出的竟然是2. 原因还是稍微深奥的. 解释下: 这里面,涉及到一个栈帧的问题. 在catch中执行的时候,ret

Java 静态代码块执行顺序

public class Test1 {public static int k=0;public static Test1 t1 = new Test1("t1");public static Test1 t2 = new Test1("t2");public static int i = print("i");public static int n = 99;public static int j = print("j");

java static块详解

1. java static块执行时机 java static块在类被初始化的时候被执行. 参考<深入Java虚拟机>中的描述,一个java class的生命周期: 装载 通过类的全限定名,产生一个代表该类型的二进制数据流: 解析这个二进制数据流为方法区内的数据结构: 创建一个表示该类型的java.lang.Class的实例. 如果一个类装载器在预先装载的时遇到缺失或错误的class文件,它需要等到程序首次主动使用该类时才报告错误. 连接 验证,确认类型符合Java语言的语义,检查各个类之间的

java中static作用详解

static表示“全局”或者“静态”的意思,用来修饰成员变量和成员方法,也可以形成静态static代码块,但是Java语言中没有全局变量的概念. 被static修饰的成员变量和成员方法独立于该类的任何对象.也就是说,它不依赖类特定的实例,被类的所有实例共享. 只要这个类被加载,Java虚拟机就能根据类名在运行时数据区的方法区内定找到他们.因此,static对象可以在它的任何对象创建之前访问,无需引用任何对象. 用public修饰的static成员变量和成员方法本质是全局变量和全局方法,当声明它类