{
System.out.println(b);
System.out.println(“非静态代码块”);
}
public StaticDemo() {
System.out.println(“构造函数”);
}
public static void main(String[] args) {
StaticDemo demo = new StaticDemo();
}
}
打印结果:
静态属性
静态代码块
非静态属性
非静态代码块
构造函数
在有继承关系的情况下
父类的静态属性和静态代码
必看视频!获取2024年最新Java开发全套学习资料 备注Java
块>子类的静态属性和静态代码块>父类的非静态属性>父类的构造函数>子类的非静态函数>子类的构造函数
再来验证一下
class ParentClass{
public static String pA = “父类-静态属性”;
public String pB = “父类-非静态属性”;
static {
System.out.println(pA);
System.out.println(“父类-静态代码块”);
}
{
System.out.println(pB);
System.out.println(“父类-非静态代码块”);
}
public ParentClass() {
System.out.println(“父类-构造函数”);
}
}
public class StaticDemo extends ParentClass{
public String b = “非静态属性”;
public static String a = “静态属性”;
static {
System.out.println(a);
System.out.println(“静态代码块”);
}
{
System.out.println(b);
System.out.println(“非静态代码块”);
}
public StaticDemo() {
System.out.println(“构造函数”);
}
public static void main(String[] args) {
StaticDemo demo = new StaticDemo();
}
}
执行结果:
父类-静态属性
父类-静态代码块
静态属性
静态代码块
父类-非静态属性
父类-非静态代码块
父类-构造函数
非静态属性
非静态代码块
构造函数
这几个问题我们知道答案了,但是为什么会产生这样的结果呢?
类是如何加载的
我们看一下类的加载过程:
graph TD
加载 --> 验证–> 准备 --> 解析–> 初始化
流程图中的过程就是一个类加载的生命周期,每个阶段会做相应的工作
- 加载:主要做了三件事:
- 获取二进制字节流,也就是通过全限定名找到这个类在哪里,是jar还是class文件
- 将静态存储结构转化为方法区运行时数据结构
- 在java堆中生成一个class类对象(相当于一个句柄,方法区的访问入口),去访问方法区
- 验证:主要就是验证类的正确性,包括魔数、版本号、常量池验证、元数据验证、字节码验证、符号引用验证等等
- 准备:为类变量分配内存并设置类变量的初始化。这些内存都在方法区分配。注意此时就会为我们的类变量也就是静态变量分配内存,但是普通成员变量还没。
还有一点需要注意的是对final修饰的类变量,在准备阶段就赋值了
static int n = 2;//初始化的值是0 而不是2 因为此时还没执行任何java方法
static final int n = 2;//初始化的值是2,ConstantValue对应到常量池,在准备阶段n被赋值成2
- 解析:对符号引用进行解析。(直接引用:指向目标的指针或者偏移量)把符号引用变为直接引用
- 初始化: 在编译生成class文件时,会自动产生两个方法,一个是类的初始化方法< clinit>, 另一个是实例的初始化方法< init>
- < init >方法 实例的初始化阶段
总结
我们总是喜欢瞻仰大厂的大神们,但实际上大神也不过凡人,与菜鸟程序员相比,也就多花了几分心思,如果你再不努力,差距也只会越来越大。实际上,作为程序员,丰富自己的知识储备,提升自己的知识深度和广度是很有必要的。
Mybatis源码解析
,丰富自己的知识储备,提升自己的知识深度和广度是很有必要的。
Mybatis源码解析
[外链图片转存中…(img-lGSzGE2i-1716464978782)]
[外链图片转存中…(img-npvMfm0s-1716464978783)]