大部分教程都会告诉我们静态初始化块和静态字段总是在初始化块和普通类字段前运行,事实上也确实如此,直到我看到下面这样的代码:

public class Test {

	static Test test = new Test();

	{
System.out.println("normal");
} static{
System.out.println("static");
} public static void main(String [] args){
Test test = new Test();
} }

可以先猜一猜结果,然后我们编译运行:

$ javac Test.java
$ java Test normal
static
normal

难道不应该是先打印出static才对吗?这里我就不卖关子了,答案很简单。我们先来看一段话:

every constructor written in the Java programming language (JLS §8.8) appears as an instance initialization method that has the special name <init>. The initialization method of a class or interface has the special name <clinit>.

这段话来自jls,意思是普通的构造函数和初始化块会被放在一个叫<init>的方法里,在创建对象实例时调用;而类自身的初始化包括静态字段和静态方法会被放在叫<clinit>的方法里。而静态字段和静态块的初始化优先级相同,顺序遵从在代码中排列的顺序,也就是谁在前面谁先执行。

因此执行顺序已经明了了:

  1. 因为main函数中要创建类的实例,所以类会先被加载,这是调用了<clinit>
  2. 静态字段在静态初始化块之前,所以先执行初始化
  3. 静态字段调用了new Test()创建类的实例,这时调用了<init>
  4. 因为普通的初始化块在<init>里,所以被调用,首先打印出了normal
  5. 静态字段初始化完成后开始执行紧随其后的静态块,打印出static
  6. 随后回到main函数中,类的初始化只会运行一次,所以这次只有<init>运行,打印出normal

因此看起来像是普通初始化块在静态块之前运行了,实际上只是静态字段的初始化导致了普通初始化块的提前执行。

知道了原理后,想下面这样的代码会输出什么自然也不在话下了:

public class Init {
private int v = 0;
static Init obj2 = new Init(); // 只能是static字段,想一想为什么 static {
System.out.println("static 2");
} static Init obj1 = new Init(); {
System.out.println("from init");
} static {
System.out.println("static 1");
} public static void main(String[] args) {
var o1 = new Init();
var o2 = new Init();
}
}

当然,在实际的编码中静态块应该只负责静态字段的处理,普通的初始化块只负责对普通类字段的处理,上面的代码是不应该被模仿的。

参考

https://www.zhihu.com/question/50374553

java中类的普通初始化块一定在静态初始化块后运行吗的更多相关文章

  1. Java学习笔记11---静态成员变量、静态代码块、成员变量及构造方法的初始化或调用顺序

    当创建一个对象时,各种成员变量及构造方法的初始化或调用顺序是怎样的呢? (1).如果类尚未加载,则先初始化静态成员变量和静态代码块,再初始化成员变量,最后调用相应的构造方法: (2).如果类已经加载过 ...

  2. JAVA程序执行顺序(静态代码块》非静态代码块》静态方法》构造函数)

    总结:静态代码块总是最先执行. 非静态代码块跟非静态方法一样,跟对象有关.只不过非静态代码块在构造函数之前执行. 父类非静态代码块.构造函数执行完毕后(相当于父类对象初始化完成), 才开始执行子类的非 ...

  3. java中静态代码块,非静态代码块,构造函数

    关于静态代码块 静态代码块的写法: static { System.out.println("我是静态代码块"); } 静态代码块的特点: 1.执行优先级高于非静态的初始化块,它会 ...

  4. Java子父类间静态代码块、非静态代码块、构造方法的执行顺序

    子类A继承父类B,A a=new A(); 正确的执行顺序是:父类B静态代码块->子类A静态代码块->父类B非静态代码块->父类B构造函数->子类A非静态代码块->子类A ...

  5. java 对象的初始化流程(静态成员、静态代码块、普通代码块、构造方法)

    一.java对象初始化过程 第一步,加载该类,一个java对象在初始化前会进行类加载,在JVM中生成Class对象.加载一个类会进行如下操作,下面给出递归描述.(关于Class对象详见反射 点击这里) ...

  6. Java中静态变量、静态代码块、非静态代码块以及静态方法的加载顺序

    在研究单例设计模式的时候,用到了静态变量和静态方法的内容,出于兴趣,这里简单了解一下这四个模块在类初始化的时候的加载顺序. 经过研究发现,它们的加载顺序为: 1.非静态代码块 2.静态变量或者静态代码 ...

  7. 浅谈Java中静态代码块和非静态代码块

    静态代码块: static{} 执行优先级高于非静态的初始化块,它会在类初始化(类初始化这个问题改天再详细讨论)的时候执行一次,执行完成便销毁,它仅能初始化类变量,即static修饰的数据成员. 非静 ...

  8. Java静态代码块与非静态代码块

    静态代码块,格式是 static{ },随着类的加载而加载,且只执行一次. 在程序中,执行的优先级最高. 非静态代码块,格式是{ },在创建对象的时候运行(即new一个对象的时候),每创建一次对象就执 ...

  9. Java的初始化块、静态初始化块、构造函数的执行顺序及用途探究

    Java与C++有一个不同之处在于,Java不但有构造函数,还有一个”初始化块“(Initialization Block)的概念.下面探究一下它的执行顺序与可能的用途. 执行顺序 首先定义A, B, ...

  10. Java提高篇——静态代码块、构造代码块、构造函数以及Java类初始化顺序

    静态代码块:用staitc声明,jvm加载类时执行,仅执行一次构造代码块:类中直接用{}定义,每一次创建对象时执行.执行顺序优先级:静态块,main(),构造块,构造方法. 构造函数 public H ...

随机推荐

  1. STL deque容器

    deque - 双向队列 1.队列的基本知识 队列的基本特性就是先进先出(FIFO),也就是第一个进去的元素第一个出来.即队列就是一个只允许在一端进行插入,在另一端进行删除操作的线性表.Queue接口 ...

  2. React 应用构建(环境)

    可以少去理解一些不必要的概念,而多去思考为什么会有这样的东西,它解决了什么问题,或者它的运行机制是什么? 一. 环境搭建 工作编辑器:Visual Studio Code. Javascript 解析 ...

  3. 如何使用 PreparedStatement 来避免 SQL 注入,并提高性能?

    前言 本篇文章主要如何使用 PreparedStatement 来避免 SQL 注入,并提高性能? 欢迎点赞 收藏 留言评论 私信必回哟 博主将持续更新学习记录收获,友友们有任何问题可以在评论区留言 ...

  4. Mongoose查增改删

    在src目录下新建一个文件夹models,用来存放数据模型和操作数据库的方法. 在models目录下新建一个文件user.js,用来管理用户信息相关的数据库操作. 相关的数据模型和数据库操作方法,最后 ...

  5. 用pycharm创建一个django框架

    用pycharm创建一个django框架 注意解释器的选择和文件路径 创建完django项目 1.自动创建了一个templates目录(先删除) 2.把settings里的 TEMPLATES = [ ...

  6. Java8新特性之-Map

    Map一些新方法的具体使用案例 1.getOrDefault:default V getOrDefault(Object key, V defaultValue) package com.qbb.th ...

  7. IDEA创建Springboot项目在application.yml配置文件配置了nacos远程注册中心,启动项目还是找localhost的问题

    项目结构如下: 报错如下: 解决办法: # 错误的 #spring.cloud.nacos.config.server-addr=192.168.137.137:8848 #spring.cloud. ...

  8. 华企盾DSC使用outlook发送加密文件提示解密插件未加载

    1.如果是非exchange邮箱,不能勾选"启用邮件白名单outlook插件(exchange邮箱建议勾选)"​ 2.如果是exchange邮箱则需要勾选"启用邮件白名单 ...

  9. Vue3节流指令封装

    节流指令 import { ObjectDirective } from 'vue' interface ThrottleEl extends HTMLElement { throttleEvent: ...

  10. java框架Mybatis的第一个程序

    1:什么是MyBatis MyBatis 是一款优秀的持久层框架 MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集的过程 MyBatis 可以使用简单的 XML 或注解来配 ...