## 類的實例化過程
#### 類的組成
* 類變量(靜態變量)
* 類初始化代碼
* 定義靜態常量時的賦值語句
* 靜態初始化代碼塊
* 類方法(靜態方法)
* 實例變量
* 實例初始化代碼
* 定義實例變量時的賦值語句
* 實例初始化代碼塊
* 構造方法
* 實例方法
#### 舉個栗子
基類 - 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-----");
}
```

> 來來來,讓我看一下當實例化`Child child = new Child()`時,程序的運行順序~
1. 準備階段(執行類的static常量的初始化)
在準備階段,虛擬機會在方法區中為Class分配內存,并設置static成員變量的初始值為默認值。這里僅僅會為static變量分配內存(static變量在方法區-常量區中),并且初始化static變量的值為其所屬類型的默認值。如:int類型初始化為0,引用類型初始化為null。
2. 初始化階段(開始真正執行類中定義的Java程序代碼)
- 虛擬機會確保先執行父類的`<clinit>()`方法,然后依次執行子類的`<clinit>()`;
- `<clinit>()`方法中執行的是對static變量進行賦值的操作,以及static語句塊中的操作;
**以上兩步可以得出一個結論:在使用類的時候,會優先執行`基類 》父類 》 子類`中的靜態變量及靜態代碼塊;**
> 之后在`new Child()`實例化子類時,會先初始化父類,然后在實例化子類;
#### 結論
**實例化過程:父類靜態代碼塊 —> 子類靜態化代碼塊 —> 父類非靜態代碼塊—> 父類構造方法 —> 子類非靜態代碼塊 —> 子類構造方法**
*****
有興趣的可以看看類加載的一個過程:

### 編譯時類型 & 運行時類型
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)