关于类加载和初始化相关的案例

总的顺序是:先父类后子类,先静态后动态,属性和代码块的初始化遵循正常的出场顺序无论是静态还是动态,但是他们总是先于构造器执行。但是还是需要通过题目的学习来加深我们的理解。

案例一

package ooptest;public class StaticDemo6 {public static void main(String[] args) {new SB();}}class SA {D d;static {System.out.println("A 1"); // 1.先从父类的静态开始}{System.out.println("A 2"); // 5.此处开始new对象(非静态相关)d = new D();// 6.顺序执行}public SA() {System.out.println("A 3"); // 10.此时调用完了自己的非静态代码块来到了构造器}}class SB extends SA {static C c = new C(); // 2.调用完了父类的静态相关来到子类的静态相关static {System.out.println("B 1"); // 4.接着按照顺序来调用自己的静态代码块 ,到此子类的所有静态都执行完毕接下来将会执行非静态相关}{System.out.println("B 2"); // 11.父类的构造器调用完成调用子类的非静态块}public SB() {System.out.println("B 3"); // 12.调用完了自己的非静态块调用自己的构造方法 }}class C {public C() {System.out.println("C"); // 3.C没有父类与静态直接调用自己的构造器  // 8.}
}class D extends C {// 7. 来到了D但是D有自己的父类所以到达C类public D() {System.out.println("D");// 9.调用完了父类的构造器会来到子类的构造器}
}

案例二

这里只写明了前三个打印的注释,后面的过程相似。

package staticment;public class Text {public static int k = 0;public static Text t1 = new Text("t1"); // 1.这里的静态属性赋有一个非静态的对象 所以停止类加载转向所有的非静态初始化 public static Text t2 = new Text("t2");// 6.由于上一句静态代码以及相关的非静态代码执行完毕所以来到了下一句静态代码的执行public static int i = print("i");public static int n = 99;public int j = print("j");// 2.这是第一个非静态属性它的赋值调用print("j")方法 // 7.原理和1的执行过程类似{// 4.现在2.处的非静态属性终于初始化完毕,所以接着来到了非静态块此时 k = 2, i = 1, n = 1   print("构造块");}static {print("静态块");}public Text(String str) {// 5.非静态块执行完毕之后来到了构造方法(它本身也是非静态的)此时k = 3, i = 2, n = 2  System.out.println((++k) + ":" + str + " i = " + i + " n = " + n);++i;++n;}public static int print(String str) {// 3.来自2.的调用此时k = 1, i = 0, n = 0  System.out.println((++k) + ":" + str + " i = " + i + " n = " + n);++n;return ++i;}public static void main(String[] args) {Text t = new Text("init");}
}

执行顺序为

1:j i = 0 n = 0

2:构造块 i = 1 n = 1

3:t1 i = 2 n = 2

4:j i = 3 n = 3

5:构造块 i = 4 n = 4

6:t2 i = 5 n = 5

7:i i = 6 n = 6

8:静态块 i = 7 n = 99

9:j i = 8 n = 100

10:构造块 i = 9 n = 101

11:init i = 10 n = 102

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

静态方法的隐藏

可以通过向上造型来验证,

A a = new B();

a.m(); // 这时执行的是A类中的静态方法。

深度加载知识

无论如何类的加载都

①先进行解析(也就是声明静态变量但是不去初始化),也就是将静态变量放入方法区并且标记,标记一个值0。相当于只定义没有赋值。

当所有的解析都过去的时候才进行初始化,初始化就是按照出场顺序来执行静态代码块和检查静态变量那里是否赋值值,如果有值得话那么就赋值,没有的话那么就将标记值赋值给静态变量。

注意:标记状态的值相当于无值它不可以直接参加运算但是可以间接的使用标记的值。类名调用。

几个案例

public class StaticDemo5 {public static void main(String[] args) {System.out.println(Demo.i);}}class Demo {static {i = 7; // 1}static int i; // 2}

执行顺序:

①进行解析,i = 0; // 这里是标记值

③执行到2处检查i是否赋值,结果2处没有赋值,所以就将标量值赋给了i

④i的最终值为7。

案例二

public class StaticDemo6 {public static void main(String[] args) {// new SDemo();System.out.println(SDemo.i);}}class SDemo {static {System.out.println(++SDemo.i); // 1}static int i = 5;}

①进行解析,i = 0; // 这里是标记值

②按照静态出现的顺序来加载。执行到1处,此时i的标记值发生了运算它改为了1。

③执行到2处检查i是否赋值,结果将5赋值给了i

④i的最终值为5。

案例3

public class StaticDemo7 {public static void main(String[] args) {System.out.println(E.i);System.out.println(E.j);}}class E {static E e = new E();// 1static int i = 5;// 2static int j;// 3static {E.i++;E.j++;}public E() {i++;j++;}}

①首先进行解析 i = 0,j = 0 //标记值

②停止静态的类加载,执行构造器中的方法,标记值发生了运算,i = 1,j = 1

③执行到2处,i = 5

④执行到3处j没有赋值,默认使用标记值1

⑤执行静态代码块i = 6,j = 2

内部类与加载顺序

内部类中不能含有静态变量

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

使用局部代码块的优点

初始化代码块/构造代码块 --- 定义在类内 --- 在创建对象的时候先于构造方法来执行一次。

局部代码块 --- 定义方法中 --- 限制变量的生命周期,以提高栈内存的利用率

静态变量

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

System.out 、System.in

注意:

1. 类是加载到方法区中---类中的所有的信息都会加载方法区中

2. 类是第一次使用的时候加载到方法区,加载之后不在移除 --- 意味着类只加载一次

静态变量能否定义到构造方法中?---不可以。--- 静态变量在类加载的时候加载到方法区;构造方法是在创建对象的时候调用,在栈内存中执行。

静态变量能否定义到构造代码块中?---不可以

注意:所有的静态只能定义在类中不能定义到代码块中,代码块也就意味着这个变量的作用域只是在当前代码块的作用域内。

关于static,abstract,final的共存

Java类的加载和代码执行顺序相关推荐

  1. Java深度历险(二)——Java类的加载、链接和初始化

    在上一篇文章中介绍了Java字节代码的操纵,其中提到了利用Java类加载器来加载修改过后的字节代码并在JVM上执行.本文接着上一篇的话题,讨论Java类的加载.链接和初始化.Java字节代码的表现形式 ...

  2. 28 Java类的加载机制、什么是类的加载、类的生命周期、加载:查找并加载类的二进制数据、连接、初始化、类加载器、双亲委派模型、自定义类加载器

    28Java类的加载机制 28.1.什么是类的加载 28.2.类的生命周期 28.2.1.加载:查找并加载类的二进制数据 28.2.2.连接 28.2.3.初始化 28.3.类加载器 28.4.类的加 ...

  3. 这篇文章绝对让你深刻理解java类的加载以及ClassLoader源码分析

    前言 package com.jvm.classloader;class Father2{public static String strFather="HelloJVM_Father&qu ...

  4. 透过现象看本质:Java类动态加载和热替换

    摘要:本文主要介绍类加载器.自定义类加载器及类的加载和卸载等内容,并举例介绍了Java类的热替换. 最近,遇到了两个和Java类的加载和卸载相关的问题: 1) 是一道关于Java的判断题:一个类被首次 ...

  5. java类的加载,链接,初始化

    Java字节代码的表现形式是字节数组(byte[]),而Java类在JVM中的表现形式是java.lang.Class类的对象.一个Java类从字节代码到能够在JVM中被使用,需要经过加载.链接和初始 ...

  6. Java 类的加载过程

    Java 类的加载过程 当程序主动使用某个类时,如果该类还没有加载到内存中,则通过以下三个步骤对类进行加载初始化: 类的加载:将类的class文件读入内存,并为之创建一个java.lang.Class ...

  7. 深入理解Java虚拟机:Java类的加载机制

    本篇内容包括:Java 类的加载机制(Jvm 结构组成.Java 类的加载).类的生命周期(加载-验证-准备-解析-初始化-使用-卸载).类加载器 以及 双亲委派模型. 一.Java 类的加载机制 1 ...

  8. 初识jvm-1.Java类的加载机制

    转载: jvm系列---纯洁的微笑 地址: http://www.ityouknow.com/jvm.html 1.什么是类的加载 类的加载指的是将类的.class文件中的二进制数据读入到内存中,将其 ...

  9. Java类的加载过程详解 面试高频!!!值得收藏!!!

    受多种情况的影响,又开始看JVM 方面的知识. 1.Java 实在过于内卷,没法不往深了学. 2.面试题问的多,被迫学习. 3.纯粹的好奇. 很喜欢一句话: 八小时内谋生活,八小时外谋发展. 望别日与 ...

最新文章

  1. SLAM从0到1——状态估计之最小二乘问题解法:最速下降法、牛顿法、高斯牛顿法、LM法...
  2. Centos更换阿里云源
  3. 监控zabbix面试题
  4. Webservice 或者HttpRequest请求的时候提示 “指定的注册表项不存在”错误 解决方案...
  5. js回调函数的理解(轉)
  6. wifiphisher 依赖_铂瑞思:总是依赖别人的话,就永远也长不大
  7. mysql isnull
  8. Spring Boot自动化配置的利弊及解决之道
  9. python文件、存储、压缩
  10. C++异常处理的开销
  11. 听指令的小方块(一)
  12. 天朝四大不正经社交软件 第一名“亮了”
  13. c语言实现统计过程控制,SPC统计过程控制
  14. 短视频抖音广告投放数据分析报告, 游戏行业抖音广告投放占比最多
  15. ​全球首个机器人抓取云竞赛落幕,华科夺冠,中国团队包揽前三
  16. 创建物理卷报错Can't open /dev/sdb5 exclusively. Mounted filesystem的问题解决过程记录
  17. prisma orm_使用Prisma和React构建RECIPE应用
  18. HYSBZ 1588 营业额统计 伸展树
  19. 程序员生涯之我见 找到自己的兴趣所在
  20. dlna 电脑连r1_电脑上dlna功能怎么用?

热门文章

  1. C++中的字符串输入输出
  2. 用Python爬虫分析上海的房租情况
  3. 一种对中定位夹具的机构设计
  4. 哪些人适合入门培训学习UI设计?
  5. 2022年高级性能测试岗面试题【面试必看】
  6. Python 爬虫初探
  7. 在Java中以空格分隔输入数组
  8. 【操作系统】实现生产者消费者模型
  9. css+css3层叠样式表标签汇总(笔记)
  10. PLSQL Developer安装、OCI库、tnsnames.ora配置