static和沒有static的區別:
*static的屬性/方法在類加載時就已經做好准備,因此類名.就可以調用,與對象存在不存在無關。
*非static的屬性/方法隸屬於對象,必須先創建對象,才能使用。
static的方法中,不能使用非靜態的屬性或者方法,必須先創建對象,然后用對象.調用;而非static的方法中,可以直接使用靜態的屬性或方法。
只有隸屬於類(所有對象共享)的屬性才能加static,static不能隨便加。
代碼塊 -- java允許直接用{}寫代碼,叫代碼塊。
*寫在類體中的代碼塊叫構造塊,每創建一個對象,構造塊都會被執行一次。
*前面加static的構造塊叫靜態代碼塊,類加載時執行一次。
對象創建的過程
a.單個對象創建的執行過程
(1)main()方法是程序的入口,使用new關鍵字創建對象時會在堆區申請內存空間;
(2)若成員變量沒有指定初始值,則采用默認初始化方式處理;
(3)若成員變量進行顯式初始化,則采用指定的初始值進行處理;
(4)執行構造塊中的代碼,可以對成員變量進行賦值操作;
(5)執行構造方法體中的代碼,可以對成員變量進行再次賦值;
(6)此時對象創建完畢,繼續向下執行;
b.子類對象創建的執行過程
(1)main()方法是程序的入口,使用new關鍵字創建對象時會在堆區申請內存空間;
(2)先加載父類再加載子類,因此先執行父類的靜態代碼塊再執行子類的靜態代碼塊;
(3)執行父類的構造塊和父類的構造方法體,此時內部的父類對象構造完畢;
(4)執行子類的構造塊和子類的構造方法體,此時子類對象構造完畢;
(5)構造完畢后繼續向下執行;
執行順序:(靜態代碼塊和靜態變量誰在前面就先執行誰)
父類靜態代變量、
父類靜態代碼塊、
子類靜態變量、
子類靜態代碼塊、
父類非靜態變量(父類實例成員變量)、
父類構造函數、
子類非靜態變量(子類實例成員變量)、
子類構造函數。
代碼示例:
package com.jdk.learn; public class ClassLoaderTest { public static void main(String[] args) { son sons=new son(); } } class parent{ private static int a=1; private static int b; private int c=initc(); static { b=1; System.out.println("1.父類靜態代碼塊:賦值b成功"); System.out.println("1.父類靜態代碼塊:a的值"+a); } int initc(){ System.out.println("3.父類成員變量賦值:---> c的值"+c); this.c=12; System.out.println("3.父類成員變量賦值:---> c的值"+c); return c; } public parent(){ System.out.println("4.父類構造方式開始執行---> a:"+a+",b:"+b); System.out.println("4.父類構造方式開始執行---> c:"+c); } } class son extends parent{ private static int sa=1; private static int sb; private int sc=initc2(); static { sb=1; System.out.println("2.子類靜態代碼塊:賦值sb成功"); System.out.println("2.子類靜態代碼塊:sa的值"+sa); } int initc2(){ System.out.println("5.子類成員變量賦值--->:sc的值"+sc); this.sc=12; return sc; } public son(){ System.out.println("6.子類構造方式開始執行---> sa:"+sa+",sb:"+sb); System.out.println("6.子類構造方式開始執行---> sc:"+sc); } }
執行結果:
1.父類靜態代碼塊:賦值b成功 1.父類靜態代碼塊:a的值1 2.子類靜態代碼塊:賦值sb成功 2.子類靜態代碼塊:sa的值1 3.父類成員變量賦值:---> c的值0 3.父類成員變量賦值:---> c的值12 4.父類構造方式開始執行---> a:1,b:1 4.父類構造方式開始執行---> c:12 5.子類成員變量賦值--->:sc的值0 6.子類構造方式開始執行---> sa:1,sb:1 6.子類構造方式開始執行---> sc:12
總結:
當我們進行new實例化進行操作的時候,JVM都進行了什么操作呢?
如果你看過深入理解jvm的話,應該會比較清楚,當我們使用new關鍵字進行實例化的時候,會進行如下幾步處理:
加載
此階段加載類的字節碼信息到內存
連接
此階段進行驗證,分配默認值,符號引用轉直接引用
初始化
為成員進行賦值等
使用
對實例進行操作比如sons.toString()
對於我們的實例而言,我們只關注連接和初始化階段即可。
連接階段我們按照類結構(成員變量(先),方法(后)等)的順序(不是書寫順序),先對變量進行賦默認值0,對象的話為null。
初始化的時候,就是對對象進行賦值,比如c執行initc()進行賦值。
參考博客:https://blog.csdn.net/u014042066/article/details/77574956