## 类的实例化过程
#### 类的组成
* 类变量(静态变量)
* 类初始化代码
* 定义静态常量时的赋值语句
* 静态初始化代码块
* 类方法(静态方法)
* 实例变量
* 实例初始化代码
* 定义实例变量时的赋值语句
* 实例初始化代码块
* 构造方法
* 实例方法
#### 举个栗子
基类 - Base.java
```
class Base {
public static int s;
public int a;
static {
System.out.println("基类静态代码块,s = " + s);
s = 1;
}
{
System.out.println("基类实例代码块,a = " + a);
a = 2;
}
public Base() {
System.out.println("基类构造方法,a = " + a);
}
public void step() {
System.out.println("基类s = " + s + ", a = " + a);
}
public static void main(String[] args) {
System.out.println("基类main方法");
}
public void action() {
step();
}
}
```
子类 - Child.java
```
class Child extends Base {
public static int s;
public int a;
static {
System.out.println("子类静态代码块,s = " + s);
s = 100;
}
{
System.out.println("子类实例代码块,a = " + a);
a = 200;
}
public Child() {
System.out.println("子类构造方法,a = " + a);
}
public static void main(String[] args) {
System.out.println("子类main方法child.s = " + s + ", Base.s = " + Base.s);
}
public void step() {
System.out.println("子类s = " + s + ", a = " + a);
}
}
```
调用方法
```
public static void main(String[] args) {
Child child = new Child();
System.out.println("\n-----begin-----");
Base base = child;
base.action();
child.action();
System.out.println("-----end-----\n");
System.out.println("-----begin-----");
System.out.println("基类.s = " + base.s + ", 基类.a = " + base.a );
System.out.println("子类.s =" + child.s + ", 子类.a = " + child.a);
System.out.println("-----end-----");
}
```
![](https://img.kancloud.cn/96/76/967615606a58e0632e6fae037d5b9f8e_558x684.png)
> 来来来,让我看一下当实例化`Child child = new Child()`时,程序的运行顺序~
1. 准备阶段(执行类的static常量的初始化)
在准备阶段,虚拟机会在方法区中为Class分配内存,并设置static成员变量的初始值为默认值。这里仅仅会为static变量分配内存(static变量在方法区-常量区中),并且初始化static变量的值为其所属类型的默认值。如:int类型初始化为0,引用类型初始化为null。
2. 初始化阶段(开始真正执行类中定义的Java程序代码)
- 虚拟机会确保先执行父类的`<clinit>()`方法,然后依次执行子类的`<clinit>()`;
- `<clinit>()`方法中执行的是对static变量进行赋值的操作,以及static语句块中的操作;
**以上两步可以得出一个结论:在使用类的时候,会优先执行`基类 》父类 》 子类`中的静态变量及静态代码块;**
> 之后在`new Child()`实例化子类时,会先初始化父类,然后在实例化子类;
#### 结论
**实例化过程:父类静态代码块 —> 子类静态化代码块 —> 父类非静态代码块—> 父类构造方法 —> 子类非静态代码块 —> 子类构造方法**
*****
有兴趣的可以看看类加载的一个过程:
![](https://img.kancloud.cn/2d/93/2d936b7d47e3ea5d5801c2db513eb3eb_458x737.png)
### 编译时类型 & 运行时类型
Java的引用变量有两个类型
1. 编译时类型:编译时类型由声明该变量时使用的类型决;(前期绑定/静态绑定)
2. 运行时类型:运行时类型由实际赋给该变量的对象决定。**如果编译时类型和运行时类型不一致,会出现所谓的多态**。
* 前期绑定:在程序执行之前进行绑定;(**实例变量、静态变量、静态方法、private方法,都是静态绑定的**)
* 运行时绑定:就是在程序运行时根据对象的类型进行绑定,也叫作动态绑定或运行时绑定;
#### 结论
**对变量的访问是静态绑定的**,无论是类变量还是实例变量。通过对象访问类变量,系统会转换为直接访问类变量`Base.变量`和`Child.变量`。
*****
### 参考与引用
[https://www.cnblogs.com/swiftma/p/5537665.html](https://www.cnblogs.com/swiftma/p/5537665.html)
[https://www.jianshu.com/p/8cab58ac37e3](https://www.jianshu.com/p/8cab58ac37e3)
[https://blog.csdn.net/love\_aym/article/details/79592489](https://blog.csdn.net/love_aym/article/details/79592489)
[https://blog.csdn.net/CrystalDestiny/article/details/13017029](https://blog.csdn.net/CrystalDestiny/article/details/13017029)
[https://www.cnblogs.com/williamjie/p/11167902.html](https://www.cnblogs.com/williamjie/p/11167902.html)
[https://www.cnblogs.com/mars-fei/p/10214934.html](https://www.cnblogs.com/mars-fei/p/10214934.html)
[https://www.cnblogs.com/suruozhong/p/6045361.html](https://www.cnblogs.com/suruozhong/p/6045361.html)