问题的引入

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

最近看到了一个比较有意思的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. 全新适配鸿蒙生态,Cocos引擎助力3D应用开发

    原文链接:https://mp.weixin.qq.com/s/rCACesJ4QxRuU2NRjIvbDQ,点击链接查看更多技术内容: 一.适配HarmonyOS背景 HarmonyOS 3.1版本 ...

  2. 树模型-LightGBM-从三个层面改进xgb

    LightGBM lightGBM总结

  3. CentOS文件备份|还原

    CentOS文件备份|还原 时间:2014-03-18 00:27 来源:51cto博客 作者:sailyangfan的空间 举报 点击:205次 dump备份 restore还原 dd数据备份 mk ...

  4. seo FAQ 科普

    前言 seo 常规问题整理,后续不断补充,只做科普. 正文 1.什么是seo: seo 也就是搜索排名. 2.百度,360等知名品牌如何排名: 抓取,过滤,建立索引,输出结果 3.是否网站越好看排名就 ...

  5. electron 关于jquery不可以用

    前言 electron 实际是在google 内核上开发,实际上和我们在浏览器还是有些区别的. jquery 在electron 上引用是会出错的. 正文 解决方案 如果不做任何操作,在Electro ...

  6. ActiveMQ c# 系列——进阶实例(三)

    前言 前面介绍了基本的消费者和生产者,那么看下他们之间有什么其他的api. 正文 消费者设置等待时间 生产者生产了5条消息 改一下消费者. static void Main(string[] args ...

  7. 重新整理数据结构与算法(c#)—— 算法套路分治算法[二十五]

    前言 有一个汉罗塔的游戏如下: 汉诺塔:汉诺塔(又称河内塔)问题是源于印度一个古老传说的益智玩具. 大梵天创造世界的时候做了三根金刚石柱子,在一根柱子上从下往上按照大小顺序摞着64片黄金圆盘. 大梵天 ...

  8. xxx,一个神奇的 Python 库

    前几天,我在<技术周刊的转变:如何平衡热爱与现实?>一文里写过国内 Python 自媒体圈在近几年的两个现象(仅个人观感,无科学数据支撑): Python 广告投放出现断崖式萎缩 Pyth ...

  9. BURP保存多个监听器配置

    "感谢您阅读本篇博客!如果您觉得本文对您有所帮助或启发,请不吝点赞和分享给更多的朋友.您的支持是我持续创作的动力,也欢迎留言交流,让我们一起探讨技术,共同成长!谢谢!" 前言 在进 ...

  10. 科普达人丨一图看懂块存储&云盘

    简介: 建议收藏 原文链接:https://click.aliyun.com/m/1000363155/ 本文为阿里云原创内容,未经允许不得转载.