问题的引入

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

最近看到了一个比较有意思的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. easyExcel合并数据导出(一对多)

    语言 java 框架 ssm 需求 :看图  也是导出效果 数据库查询为(关系为一对多) 一个学生对应多个课程 实现步骤 1.实体类配置, 建议单独写个实体用来导出使用() 学生信息字段正常配置  , ...

  2. HarmonyOS音频通话开发指导

      常用的音频通话模式包括VOIP通话和蜂窝通话. ● VOIP通话:VOIP(Voice over Internet Protocol)通话是指基于互联网协议(IP)进行通讯的一种语音通话技术.VO ...

  3. 刪除k个数字后的最小值

    前言 比如说 1593212,去掉一个数字后,保留的是最小值. 原理:因为要保留最小值,那么要删除最高位的数字是最明显的. 那么1和5到底删除哪一个呢?当然是删除最大值了. 代码 public sta ...

  4. 通过UI自动化方式获取文章、视频信息

    出于学习研究,对某账号的文章.视频分析一翻,尝试使用自动化方式看能否获取相应信息. 获取某号的文章有多重方法: 第一种是通过搜狗浏览器搜索账号(这种方式每天只能获取一篇文章,基本上没啥用.): 第二种 ...

  5. Hadoop HDFS 3.2的部署

    之前写过HDFS 2.6的部署,最近项目中尝试使用最新的HDFS 3.2.1做离线存储,部署方式略有不同,所以这里再简单写一下,这里只涉及到存储因此不再配置yarn,只配置HDFS最基本的服务Name ...

  6. T-SQL中执行存储过程与C#执行同样操作的比较

    1 exec sp_executesql N"UPDATE [dbo].[Courses] 2 SET [Title] = @0 3 WHERE (([CourseID] = @1) AND ...

  7. 面试题45(Java)-把数组排成最小的数(中等)

    题目: 输入一个非负整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个. 示例 1: 输入: [10,2] 输出: "102" 示例 2: 输入: [ ...

  8. 急速上线 Serverless 钉钉机器人“防疫精灵”

    新型冠状病毒疫情肆虐的春节,大家都过得人心惶惶,作为被关在家的程序狗,总觉得要做点什么.于是阿里云 IoT 事业部的几个同学就开始了防疫精灵的开发之路. 从点子到防疫宝,只花了一个下午时间:从防疫宝到 ...

  9. [FAQ] jQuery prop 与 attr 的区别

    .prop() 获取匹配的元素集中第一个元素的属性(property)值 或 设置每一个匹配元素的一个或多个属性. 当设置 selectedIndex, tagName, nodeName, node ...

  10. [FAQ] Goland 始终没有包代码的提示 ?

    表现:import 引入的包始终是红色的,表示没有找到引入的包. 注意,在这里开启Go Modules: 然后在 Exteneral Libraries 里看到 Go Modules 即可. Refe ...