Java代码加载顺序

  • 代码块
  • 类加载和初始化相关案例一
  • 案例二
  • 深度加载知识
  • 静态变量
  • 内部类中不能定义静态变量

代码块

项目 Value 作用
局部代码块 在main方法里面 给变量限定声明周期,局部代码块的变量在执行结束后会被Java回收
构造代码块(非静态代码块) 在类的成员位置 在每次执行构造方法前先执行构造代码块。可以将多个构造方法中的相同的代码放到构造代码块中,对对象进行初始化。
静态代码块 在类的成员位置 一般用于给类初始化,被静态修饰的代码块仅执行一次。

1、代码执行顺序:静态代码块—>main方法的代码 —>构造代码块 —>构造方法 —>顺序执行代码(或同步代码块)。
2、父类静态代码块 —> 子类静态代码块 —> main方法的代码 —> 父类构造代码块 —> 父类构造方法 —> 子类构造代码块 —> 子类构造方法 —> 顺序执行代码(包括普通代码块、同步代码块)(当父类无super时,触发子类有参构造函数和无参构造函数时只调用父类无参构造函数)

类加载和初始化相关案例一

package classloader;public class TestStatic {static {//1.main方法所在类的静态代码块,打印static;System.out.println("static");}//开始执行main方法;public static void main(String[] args) {//2.执行main方法中的代码。new一个B的实例,进入到类B;new ClassB();}
}class ClassA{ClassD d;static {//3.从ClassB进入从父类ClassA的静态代码块,打印ClassA 1;System.out.println("ClassA 1");}{//7.执行父类的构造代码块,打印ClassA 2;System.out.println("ClassA 2");//8.此处开始new对象(非静态相关)。d = new ClassD();}public ClassA(){//11.执行完ClassA的构造代码块,执行构造方法,打印ClassA 3;System.out.println("ClassA 3");}
}
//ClassB有父类ClassA
class ClassB extends ClassA{//4.调用完了父类的静态相关来到子类的静态相关static ClassC classC = new ClassC();static {//6.按照顺序来调用自己的静态代码块,到此子类的所有静态都执行完毕接下来将会执行非静态相关,打印ClassB 1;System.out.println("ClassB 1");}{//12.执行完父类构造方法,执行子类的非静态块,打印ClassB 2;System.out.println("ClassB 2");}public ClassB() {//13.调用完自己的非静态块调用自己的构造方法,打印ClassB 3。System.out.println("ClassB 3");}
}class ClassC{public ClassC() {//5.new ClassC的时候,ClassC没有父类,没有静态代码块,没有构造代码块,直接执行构造方法,打印ClassC;//9.在new ClassD的时候,ClassD有父类ClassC,父类中没有静态代码,子类中没有静态代码;父类中也没有构造代码块,执行父类的构造方法,打印ClassC;System.out.println("ClassC");}
}
//ClassD有父类 ClassC
class ClassD extends ClassC{public ClassD() {//10.调用完父类构造方法,由于子类没有构造代码块,直接执行子类构造方法,打印ClassDSystem.out.println("ClassD");}
}
  1. 当执行TestStatic类中的main方法时,由于该类没有父类,但是有静态代码块,所以先执行静态代码块中的代码,在控制台打印static;
  2. 执行main方法中的代码,初始化一个ClassB,由于ClassB有父类,所以先调用父类ClassA中的静态代码块,所以在控制台打印ClassA 1;
  3. 执行子类即ClassB中的静态代码块,ClassC的实例化与初始化。ClassC没有父类,没有静态代码块,没有构造代码块,直接执行ClassC中的构造方法,在控制台打印ClassC;
  4. 回到ClassB,继续执行静态代码块,在控制台打印 ClassB1;
  5. 执行完ClassB的静态代码,执行父类ClassA的构造代码块,在控制台打印ClassA 2;
  6. 执行父类ClassA的构造代码块是初始化一个ClassD,ClassD有父类ClassC,父类ClassC中没有静态代码块,ClassD中也没有静态代码块,父类ClassC中也没有构造代码块,执行构造方法,在控制台打印ClassC;
  7. 执行完父类ClassC中的构造方法,由于子类ClassD中没有构造代码块,执行构造方法,在控制台打印ClassD;
  8. 回到ClassA,执行完构造代码块,执行构造方法,在控制台打印ClassA 3;
  9. 再回到ClassB中,执行构造代码块,在控制台打印ClassB 2;
    10.执行ClassB的构造方法,在控制台打印ClassB 3。

案例二

package classloader;public class Text {//1)执行main方法public static void main(String[] args) {// 24)执行main方法中的代码,直接调用构造方法Text t = new Text("init");}//2)首先执行main方法所在类的静态相关代码, k = 0;public static int k = 0;//3)这里的静态属性赋有一个非静态的对象 所以停止类加载转向所有的非静态初始化public static Text t1 = new Text("t1");// 9)由于上一句静态代码以及相关的非静态代码执行完毕所以来到了下一句静态代码的执行public static Text t2 = new Text("t2");// 15) 由于上一句静态代码以及相关的非静态代码执行完毕所以来到了下一句静态代码的执行public static int i = print("i");//17) 由于上一句静态代码以及相关的非静态代码执行完毕所以来到了下一句静态代码的执行public static int n = 99;// 4)这是第一个非静态属性它的赋值调用print("j")方法// 10)原理和3)的执行过程类似,调用print("j")// 20)执行非静态代码,调用print("j")public int j = print("j");{// 6)现在4)处的非静态属性终于初始化完毕,所以接着来到了非静态块// 12)现在10)处的非静态属性初始化完毕,执行非静态代码块// 22)执行非静态代码块print("构造块");}static {//18)执行该静态代码块print("静态块");}// 8)非静态块执行完毕之后来到了构造方法(它本身也是非静态的)此时k = 2, i = 2, n = 2, 打印 3 : t1 i = 2 n = 2;// 14) 非静态块执行完毕之后来到了构造方法(它本身也是非静态的)此时k = 5, i = 5, n = 5, 打印 6 : t2 i = 5 n =5// 25) 类加载完毕,直接调用构造方法,此时k = 10, i = 10, n = 102,打印 11 : init i = 10 n = 102public Text(String str) {System.out.println((++k) + ":" + str + " i = " + i + " n = " + n);++i;++n;}// 5)来自4)的调用此时k = 0, i = 0, n = 0, 打印 1 : j i = 0 n = 0// 7)来自6)的调用此时k = 1, i = 1, n = 1, 打印 2 : 构造块 i = 1 n = 1// 11) 来自10)的调用此时 k = 3, i = 3, n = 3, 打印 4 : j i = 3 n = 3// 13)来自12)的调用此时 k = 4, i = 4, n = 4, 打印 5 : 构造块 i = 4 n = 4// 16)来自15)的调用此时 k = 6, i = 6, n = 6, 打印 7 : i i = 6 n = 6// 19)来自18)的调用此时 k = 7, i = 7, n = 99,打印 8 : 静态块 i = 7 n = 99// 21)来自20)的调用此时 k = 8, i = 8, n = 100,打印 9 : j i = 8 n = 100// 23)来自22)的调用此时 k = 9, i = 9, n = 101,打印 10 : 构造快 i = 9 n = 101public static int print(String str) {System.out.println((++k) + ":" + str + " i = " + i + " n = " + n);++n;return ++i;}
}

注意:当加载到一个静态属性的时候他的赋值对象为一个静态的对象,这个时候就会中断静态相关的加载,转而先去执行非静态相关的代码。这里还需要注意的是属性和代码块的加载遵循他们的先后出场顺序。

深度加载知识

所有的类加载

  1. 先进行解析(也就是声明静态变量但是不去初始化),也就是将静态变量放入方法区并且标记,标记一个值0。相当于只定义没有赋值。
  2. 当所有的解析都过去的时候才进行初始化,初始化就是按照出场顺序来执行静态代码块和检查静态变量那里是否赋值,如果有值的话那么就赋值,没有的话那么就将标记值赋值给静态变量。
  3. 标记状态的值相当于无值,它不可以直接参加运算但是可以间接的使用标记的值。类名调用。

静态变量

static修饰的变量是静态变量。静态变量在类加载的时候加载到方法区,并且在方法区中被赋予默认值。由于静态变量先于对象出现,所以可以通过类名来调用静态变量,也可以通过对象调用。这个类的所有对象存储的是这个静态变量在方法区中的地址,所以所有对象共享这个静态变量。
注意:

  1. 类是加载到方法区中—类中的所有信息都会加载方法区中
  2. 类是第一次使用的时候加载到方法区,加载之后不在移除—意味着类只加载一次
  3. 静态变量不能定义在构造方法中。静态变量在类加载的时候加载到方法区;构造方法是在创建对象的时候调用,在栈内存中执行。
  4. 静态变量不能定义在构造代码块中。所有的静态变量只能定义在类中,不能定义在代码块中,代码块也就意味着这个变量的作用域只是在当前代码块的作用域内。

内部类中不能定义静态变量

静态变量是要占用内存的,在编译时只要是静态变量,系统就会自动分配内存给他,而内部类是在宿主类编译完编译的,也就是说,必须有宿主类存在后才能有内部类,这也就和编译时就为静态变量分配内存产生了冲突,因为系统执行:运行宿主类—>静态变量内存分配—>内部类,而此时内部类的静态变量先于内部类生成,这显然是不可能的,所以内部类中不能定义静态变量。

Java基础:Java代码加载顺序相关推荐

  1. HTML基础和JSP了解及JSP中代码加载顺序

    HTML入门基础教程 html是什么,什么是html通俗解答: html是hypertext markup language的缩写,即超文本标记语言.html是用于创建可从一个平台移植到另一平台的超文 ...

  2. Java static作用及加载顺序

    在java中,static可以修饰成员变量.成员方法.代码块.内部类. static修饰成员变量,可以达到全局变量的效果(Java没有全局变量的概念),当一个类定义了static变量,其实就是申请一个 ...

  3. 关于java中类成员的加载顺序

    目录 一.单个类的加载顺序 二.代码 三.输出结果 三.对输出结果的解释 四.类加载的内存图: 一.单个类的加载顺序 1.加载是类 2.产生自己的静态空间 静态属性 静态方法 静态块 执行静态块 3. ...

  4. java代码加载_java类中代码加载顺序

    package org.senssic; /** * 一般顺序:静态块-->静态变量-->成员变量-->构造方法-->静态方法(或非静态方法,需要调用) * 1.静态代码块(只 ...

  5. Java 基础——类的加载

    当程序主动使用某个类时,如果该类还未被加载到内存中,系统会通过加载,连接,初始化三个步骤来对该类进行初始化,JVM将会连续完成这三个步骤,也把这三个步骤统称为类加载或类初始化: 类加载指的是将类Cla ...

  6. java中静态变量,静态代码块,静态方法,实例变量,匿名代码块的加载顺序

    1. java中静态变量,静态代码块,静态方法,实例变量,匿名代码块 在Java中,使用{}括起来的代码称为代码块,代码块可以分为以下四种: (1)普通代码块:就是类中方法的方法体 public vo ...

  7. Java基础之代码执行顺序深入解析

    Java基础之代码执行顺序深入解析 结合实例代码分析: public class demo6 {public static void main(String[] args) {new Son();Sy ...

  8. Java内部类以及类的加载顺序(一)

    java内部类以及类的加载顺序(一) Java 类中不仅可以定义变量和方法,还可以定义类,这样定义在类内部的类就被称为内部类.根据定义的方式不同,内部类分为四大类静态内部类,成员内部类,局部内部类,匿 ...

  9. java静态方法加载顺序_java中类以及方法的加载顺序

    先看下面的代码: public class Test { public static int a =0 ; static { a = 10; System.out.println("静态代码 ...

最新文章

  1. 小米4手机在DDMS下获取data/data目录权限
  2. 嵌入式linux内存使用和性能优化
  3. dubbo之注册管理中心
  4. 在线分析|在线做随机森林分析
  5. 2.6内核中被废弃的pci_present()
  6. js 导出到excel
  7. 注意!在subList生成子列表之后,一定不要随便更改原列表
  8. 360极速模式和兼容模式对页面的影响
  9. 500万数据mysql_mysql 单表500万数据经过处理后新增到新表
  10. SAP License:物料编码原则<外部分配还是内部分配>之三
  11. 另类方法激活你的Winodws 2008
  12. 《计算机网络 第七版》读后感
  13. 排序算法(天勤数据结构高分笔记)
  14. 后台管理系统 - 权限设计
  15. o2o模式的特点是什么 O2O商业模式与新零售有什么区别?
  16. HDMI设计9--Video Mixer IP
  17. 详解MOVE PROTOCOL的测试版,让健康运动如影随形
  18. html中写页边距,html整体页面边距怎么设置
  19. Qt实现双击可编辑的QLabel,输入文本后回车确定
  20. 前端构建工具gulpjs的使用介绍及技巧

热门文章

  1. 火拼折叠屏:国产手机的杀手锏还是遮羞布?
  2. 2021年的时间的朋友还在真好
  3. 2010励志篇:给自己的一封信
  4. OkHttp原理分析总结
  5. NetXpert XG轻松应对10Gb/s以太网光纤测试新挑战
  6. BP神经网络非线性函数拟合
  7. Window关闭端口的方法(445/135/137/138/139/3389等)
  8. bcompiler php,bcompiler 函数
  9. java笔记冯佳微盘,JAVA学习笔记14 - osc_vsdge2u3的个人空间 - OSCHINA - 中文开源技术交流社区...
  10. Unity 优化(Draw Call)