java對象的初始化
小冬(珠海)11:02:48
我們知道一個對象可以有靜態變量、變量、靜態初始化塊、初始化塊,當我們創建一個對象時,它是怎么初始化的呢?按什么順序初始化的呢?
- public class Test {
-
-
- // 靜態變量
- public static String staticField = "靜態變量"; // 變量
- public String field = "變量";
- // 靜態初始化塊
- static {
- System.out.println(staticField);
- System.out.println("靜態初始化塊");
- }
- // 初始化塊
- {
- System.out.println(field);
- System.out.println("初始化塊");
- }
- // 構造器
- public Test() {
- System.out.println("構造器");
- }
- public static void main(String[] args) {
- Test test = new Testb();
-
- }
- }
運行下代碼,輸出結果是:
靜態變量
靜態初始化塊
變量
初始化塊
構造器
由此可以看到,當new一個對象時,它并不是就是調構造方法,而是先初始化屬性變量,我們把變量的定義先后順序換下,再執行,會發現,靜態的是先于非靜態進行實始化的,那么對于靜態變量和靜態初始化塊之間、變量和初始化塊之間的先后順序又是怎樣呢?是否靜態變量總是先于靜態初始化塊,變量總是先于初始化塊就被初始化了呢?
我們先改下代碼:
- public class Test {
-
- public static TestA ta = new TestA();
- // 靜態變量
- public static String staticField = "靜態變量"; // 變量
- public String field = "變量";
- // 靜態初始化塊
- static {
- System.out.println(staticField);
- System.out.println("靜態初始化塊");
- }
- // 初始化塊
- {
- System.out.println(field);
- System.out.println("初始化塊");
- }
- // 構造器
- public Test() {
- System.out.println("構造器");
- }
- public static void main(String[] args) {
- Test test = new Test();
-
- }
- }
-
- class TestA {
- public TestA() {
- System.out.println("Test--A");
- }
- }
輸出是:
Test--A
靜態變量
靜態初始化塊
變量
初始化塊
構造器
靜態變量:static TestA ta = new TestA()在靜態初始化塊前,所以先輸出Test--A
再換下位置,把static TestA ta = new TestA()放到在靜態初始化塊后,我們發現輸出是:
靜態變量
靜態初始化塊
Test--A
變量
初始化塊
構造器
由此可見這是取決于它們在類中出現的先后順序,同理可得:變量和初始化塊之間也如此,總結可得:初始化優先級是(靜態變量/靜態初始化塊)>(變量/初始化塊)>構造器。
那繼承關系時的初始化又是怎樣的呢?如下:
大家應該知道,初始化子類時會先初始化父類,再看代碼:
- public class Test extends Parent{
- // 靜態變量
- public static String staticField = "子類靜態變量"; // 變量
- public String field = "子類變量";
- // 靜態初始化塊
- static {
- System.out.println(staticField);
- System.out.println("子類靜態初始化塊");
- }
- //public static TestA ta = new TestA();
- // 初始化塊
- {
- System.out.println(field);
- System.out.println("子類初始化塊");
- }
- // 構造器
- public Test() {
- System.out.println("子類構造器");
- }
- public static void main(String[] args) {
- Test test = new Test();
- }
- }
-
- class Parent{
-
- public String field = "父類變量";// 變量
- public static String staticField = "父類靜態變量"; // 靜態變量
- // 靜態初始化塊
- static {
- System.out.println(staticField);
- System.out.println("父類靜態初始化塊");
- }
- // 初始化塊
- {
- System.out.println(field);
- System.out.println("父類初始化塊");
- }
- // 構造器
- public Parent() {
- System.out.println("父類構造器");
- }
- }
剛才結果應該是:
父類靜態變量
父類靜態初始化塊
子類靜態變量
子類靜態初始化塊
父類變量
父類初始化塊
父類構造器
子類變量
子類初始化塊
子類構造器
從結果看到,并不是父類完全初始化完后再進行子類的初始化,子類的靜態變量和靜態初始化塊的初始化是在父類的變量、初始化塊和構造器初始化之前就完成了。
我們在main方法再創建一個對象,Test test2 = new Test();
大家就test2的初始化又如何?
為了好看,我們子類構造器里加多行代碼System.out.println("***********");
輸出結果:
父類靜態變量
父類靜態初始化塊
子類靜態變量
子類靜態初始化塊
父類變量
父類初始化塊
父類構造器
子類變量
子類初始化塊
子類構造器
***********
父類變量
父類初始化塊
父類構造器
子類變量
子類初始化塊
子類構造器
***********
發現什么了?
靜態變量和靜態代碼塊只加載一次 。
總結:
一、初始化優先級:
1、靜態變量/靜態初始化塊)>(變量/初始化塊)>構造器
2、父類>子類
二、靜態變量和靜態代碼塊只加載一次,因為它們是全局共享的