ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
## 类的实例化过程 #### 类的组成 * 类变量(静态变量) * 类初始化代码 * 定义静态常量时的赋值语句 * 静态初始化代码块 * 类方法(静态方法) * 实例变量 * 实例初始化代码 * 定义实例变量时的赋值语句 * 实例初始化代码块 * 构造方法 * 实例方法 #### 举个栗子 基类 - 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)