类初始化步骤
- 假如一个类还没有被加载或者连接,那就先加载和连接这个类
- 假如类存在直接的父类,并且这个父类还没有被初始化,那就先初始化直接的父类
- 假如类中存在初始化语句,那就直接按顺序执行这些初始化语句
类的初始化
在类的生命周期执行完加载和连接之后就开始了类的初始化。在类的初始化阶段,java虚拟机
执行类的初始化语句,为类的静态变量赋值,在程序中,类的初始化有两种途径:(1)在变
量的声明处赋值。(2)在静态代码处
1
2
3
4
5
6
7
8 public class Test
{
public static int a = 0; //(1)
public static int b ;
static{
b=2; //(2)
}
}
Java程序对类的使用方式可分为两种
所有的Java虚拟机实现必须在每个类或接口被Java程序“首次主动使用”时才初始化他们
- 被动使用
- 主动使用
- 创建类的实例
- 访问某个类或接口的静态变量,或者对该静态变量赋值
- 调用类的静态方法
- 反射(如Class.forName(“com.bzu.csh.Test”))
- 初始化一个类的子类
- Java虚拟机启动时被标明为启动类的类(Java Test)
变量初始化顺序
1 | public class Child extends Father { |
运行结果
父类静态成员变量
子类静态成员变量
父类实例变量
子类tellName: null
子类代码块1
子类实例变量
子类代码块2
子类tellName: 子类
---
父类实例变量
子类tellName: null
子类代码块1
子类实例变量
子类代码块2
子类tellName: 子类
解析
- 初始化顺序:
先初始化父类的静态代码—>初始化子类的静态代码–>
(创建实例时,如果不创建实例,则后面的不执行)初始化父类的非静态代码(变量定义等)——>初始化父类构造函数——>初始化子类非静态代码(变量定义等)——>初始化子类构造函数 (ps:静态(变量、代码块)地位相同。 实例变量、构造代码块地位相同 都是按照代码的先后顺序执行 并且静态优先于非静态,静态当类第一次被初始化就执行且仅执行一次)
通过 javap -c Child
查看编译后的class
调用对象的实例初始化方法,在java的class文件中称之为\< init >()方法.
简单理解就是说< init >()
就是从class文件字节码角度的构造函数,一般由Java代码里面的几部分构成。
超类的
< init >()
方法调用———————>对应super()
任意实例变量初始化方法的字节码————>对应定义变量时的赋值代码
实现了对应构造方法的方法体的字节码——>构造函数里面的代码
- 第一次输出子类tellName: null 的原因
- super();调用Father类的init<>()
- 调用super()也就是Object类的init<>()
- 给父类的name赋值
- 执行父类的构造方法:执行构造方法是在子类中调用的,此时this是子类,所以tellName、printName方法都在子类中调用,而此时子类还没有被初始化,此时name还是null故输出name为null(ps:可以查看类的生命周期, 引用类型变量在类未初始化的默认值为null)
- 子类的name开始赋值
- 执行子类的构造方法