问题的引入

还是老规矩,先说说自己遇到的问题。

最近看到了一个比较有意思的Java程序,初次看到这段程序执行的结果还是挺让我意外的,话不多说先上程序,大家也可以揣摩一下(大神自行略过......)

class Singleton{
private static Singleton singleton=new Singleton();
public static int count1=0;
public static int count2; private Singleton(){
count1++;
count2++;
}
public static Singleton getInstance(){
return singleton;
}
} public class MyTest {
public static void main(String[] args) {
Singleton instance = Singleton.getInstance();
System.out.println("count1:"+instance.count1);
System.out.println("count2:"+instance.count2);
}
}

看到这里我想大家已经有了这个程序的结果了把。不知道大家的结果是否正确:

如果你对这个结果很意外那请你接着往下看吧,嘻嘻。如果你答对了,如果你答对了也建议你看完这篇博文,或许你可以收获一点东西,让你的思路更加清晰。

知识点回顾

(敲黑板了,敲黑板了)
  首先我们需要明确的就是,在Java中静态变量如果在定义时赋初值实际上就是在在静态代码块中赋初值,(这一过程我们可以通过反编译工具查看细节,这里不做赘述);同样的非静态成员的如果在定义时赋初值,实际上就是在构造器的第一行初始化的改变量。

也就是说上面的代码在编译后,会自动将代代码编程这样

class Singleton{
private static Singleton singleton;
public static int count1=0;
public static int count2;
static{
singleton=new Singleton();
count1=0;
} private Singleton(){
count1++;
count2++;
}
public static Singleton getInstance(){
return singleton;
}
} public class MyTest {
public static void main(String[] args) {
Singleton instance = Singleton.getInstance();
System.out.println("count1:"+instance.count1);
System.out.println("count2:"+instance.count2);
}
}

上面的这个可以通过反编译工具查看,但是部分反编译工具反编译后的效果仍然是我第一次写的那样,但这些都不是重点,我们只需要知道实际上,在定义静态变量时附的初始值实际上在编译后会移到静态代码块中进行,而静态代码块的作用域构造器的优点相似,都是用于初始化,但是不同的是构造器是用于初始化非静态变量的,而静态代码块是用于初始化静态变量的。

上面就是通过XJad反编译工具打开的效果,注意最后的静态代码块(不同的反编译工具,反编译后的代码会有差异)

回顾这一个知识点,就是明确类的静态变量的初始化,是在静态代码块中进行的。

回到正题

我们都知道,一个类在被首次主动使用之前会被类加载进内存并初始化,而在初始化之前,JVM到底做了些什么呢?这里我们来简单的说一下。

类加载的步骤:

第一步:类的加载

第二步:连接

第三步:类的初始化

类的加载

类的加载指的是将.class文件加载进内存

连接

连接就是将已经读入到内存的类的二进制数据合并到虚拟机运行时环境中去。

连接也分为三步:

第一步:验证

确保加载的字节码文件的正确性

第二步:准备

为类的静态变量分配内存,并将初始化默认值。short,int,long的默认值为0,boolean的默认值为false,引用类型的默认                           值为null.

第三步:解析

把类中的符号引用转换为直接引用。

类的初始化

        为类的静态变量赋予正确的初始值,实际上就是执行静态代码块中的内容。

由上面的的描述我们就知道,一个类加载进内存会先为静态变量分配内存,并指定初始值。最后一步才执行初始化。

代码分析

我们在执行Singleton instance = Singleton.getInstance();时,由于此时Singleton还没被加载进虚拟机,所以虚拟机会自动的加载它,在连接阶段会为singleton,count1,count2分配内存,并赋上初始值。在连接阶段完成后会进行类的初始化,这一过程实际上就是执行类的静态代码块,首先会先执行singleton=new Singleton();,执行完毕后,count1和count2都为1。然后执行count1=0,此时count1等于0,count2等于1,这也就是最后输出的结果。

思考:如果把代码改成这样会输出什么?

class Singleton{
public static int count1=0;
private static Singleton singleton=new Singleton();
public static int count2=0; private Singleton(){
count1++;
count2++;
}
public static Singleton getInstance(){
return singleton;
}
} public class MyTest {
public static void main(String[] args) {
Singleton instance = Singleton.getInstance();
System.out.println("count1:"+instance.count1);
System.out.println("count2:"+instance.count2);
}
}

答案:count1=1 count2=0

总结

一个类被加载进内存分为类的加载、连接、初始化三个阶段。

一个类的静态变量的初始值是在类加载过程中的连接阶段中完成的,而类的初始化过程就是在类的初始化阶段中完成的,这个阶段中会执行静态代码块,为静态变量赋予正确的值。(程序员想要的指定的值)

Java类加载过程&&静态代码块的初始化过程的更多相关文章

  1. java基础课程笔记 static 主函数 静态工具类 classpath java文档注释 静态代码块 对象初始化过程 设计模式 继承 子父类中的函数 继承中的构造函数 对象转型 多态 封装 抽象类 final 接口 包 jar包

    Static那些事儿 Static关键字 被static修饰的变量成为静态变量(类变量) 作用:是一个修饰符,用于修饰成员(成员变量,成员方法) 1.被static修饰后的成员变量只有一份 2.当成员 ...

  2. “全栈2019”Java第四十二章:静态代码块与初始化顺序

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第 ...

  3. 面向对象设计中private,public,protected的访问控制原则及静态代码块的初始化顺序

    第一:private, public, protected访问标号的访问范围. private:只能由          1.该类中的函数          2.其友元函数访问 不能被任何其他访问,该 ...

  4. Java面试题 静态代码块 构造代码块 构造方法 的执行顺序

    JAVA中的静态代码块 构造代码块 构造方法执行顺序: 静态代码块(类加载时执行)>>构造代码块>>构造方法 下面展示一个简单的例子,推荐大家动手运行一遍: public cl ...

  5. Java之static静态代码块

    Java之static静态代码块 构造代码块 使用{}包裹的代码区域,这里的代码区域特指位于class{}下面的而不是存在于其他type method(){}这类函数下面的代码区域 public cl ...

  6. java基础之静态代码块,局部代码块,构造代码块区别。

    java中有几种常见的代码块,那怎样区别他们呢? 这里就这些问题,浅谈下我个人的理解. 1.局部代码块 局部代码块,又叫普通代码块.它是作用在方法中的代码块.例如: public void show( ...

  7. 5.1JAVA基础复习——JAVA中的静态代码块、构造代码块、构造函数、局部代码块区别

    构造代码块: 在类中定义可以给所有对象进行初始化.局部代码块: 在方法中定义属性的生命周期.静态代码块: 在类中定义用于给类调用时属性的初始化 构造函数与构造代码块的区别: 构造函数是给对应的对象进行 ...

  8. 非静态代码块(非static初始化块)&静态代码块(static初始化块)

    非静态代码块: TestOrder: package com.aff.singleton; /* 类的第四个成员:初始化块(代码块) 代码块: 如果有修饰的话只能使用static 分类:非静态代码块: ...

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

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

  10. java静态代码块、初始化块和构造方法的执行顺序

    分析:当执行new Child()时,它首先去看父类里面有没有静态代码块,如果有,它先去执行父类里面静态代码块里面的内容,当父类的静态代码块里面的内容执行完毕之后,接着去执行子类(自己这个类)里面的静 ...

随机推荐

  1. 重新整理.net core 计1400篇[九] (.net core 中的依赖注入的服务的消费)

    前言 包含服务注册信息IServiceCollection 集合最终被用来创建作为依赖注入容器的IServiceProvider 对象. 当需要创建某个服务实例的时候(服务消费),我们通过指定服务类型 ...

  2. jenkins 持续集成和交付——一个构件小栗子前置(三)

    前言 下面介绍构建一个小栗子. 在此之前有个小前提,就是已经安装好了git 服务器,用的是gogs,详细请看外篇. 正文 插件安装 首先你要安装一个git插件. 装完git插件后,我们还得安装一些gi ...

  3. 重新整理数据结构与算法(c#)——算法套路k克鲁斯算法[三十]

    前言 这个和前面一节有关系,是这样子的,前面是用顶点作为参照条件,这个是用边作为参照条件. 正文 图解如下: 每次选择最小的边. 但是会遇到一个小问题,就是会构成回路. 比如说第四步中,最小边是CE, ...

  4. wandb一个简单demo

    wandb绘制曲线:sin函数,cos函数,log函数. wandb绘制本地图片 wandb绘制matplotlib图片 wandb绘制numpy图片 import math import wandb ...

  5. 实训篇-Html-超链接a标签使用

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title> ...

  6. 构建RAG应用-day01: 词向量和向量数据库 文档预处理

    词向量和向量数据库 词向量(Embeddings)是一种将非结构化数据,如单词.句子或者整个文档,转化为实数向量的技术. 词向量搜索和关键词搜索的比较 优势1:词向量可以语义搜索 比如百度搜索,使用的 ...

  7. js 实现双指缩放

    前言随着智能手机.平板电脑等触控设备的普及,交互方式也发生了改变.相对于使用鼠标和键盘进行交互的电脑,触控设备可以直接使用手指进行交互,而且基本上都支持多点触控.多点触控最常见的操作莫过于双指缩放了. ...

  8. Asp-Net-Core开发笔记:使用alpine镜像并加入健康检查

    前言 使用 docker 部署 AspNetCore 应用已经是标配了,之前我一直使用 mcr.microsoft.com/dotnet/aspnet:8.0 这类镜像,简单粗暴,不过可以使用 alp ...

  9. 国内chatGPT中文版网站有哪些?国内人工智能百花齐放!该如何选择?

    人工智能技术在中国的快速发展和普及,使得国内的人工智能产业日益壮大.在这些领域中,自然语言处理技术和聊天机器人已经取得了显著的进展.ChatGPT作为一种基于深度学习的聊天机器人模型,在国内得到了广泛 ...

  10. eclipse 汉化语言包/中文补丁/简中设置/中英互换

    eclipse 汉化语言包/中文补丁/简中设置/中英互换 汉化很简单,使用eclipse内置的软件下载就可以,不需要下载压缩包 官方的说明 Open the install wizard with ' ...