java中類載入與靜態變數、靜態方法與靜態程式碼塊詳解與初始化順序
我們知道java中類的生命週期為裝載、連線、初始化、使用和解除安裝五個過程,如下圖所示:
1.載入
我們編寫一個java類的程式碼,經過編譯之後生成一個字尾名為.class的檔案,java虛擬機器就能識別這種檔案。java的生命週期就是class檔案從載入到消亡的過程。 關於載入,其實,就是將原始檔的class檔案找到類的資訊將其載入到方法區中,然後在堆區中例項化一個java.lang.Class物件,作為方法區中這個類的資訊的入口。但是這一功能是在JVM之外實現的,主要的原因是方便讓應用程式自己決定如何獲取這個類,在不同的虛擬機器實現的方式不一定相同,hotspot虛擬機器是採用需要時在載入的方式,
2.連線
連線一般是載入階段和初始化階段交叉進行,過程由以下三部分組成:
(1)驗證:確定該類是否符合java語言的規範,有沒有屬性和行為的重複,繼承是否合理,總之,就是保證jvm能夠執行
(2)準備:主要做的就是為由static修飾的成員變數分配記憶體,並設定預設的初始值
預設初始值如下:
1.八種基本資料型別預設的初始值是0
2.引用型別預設的初始值是null
3.有static final修飾的會直接賦值,例如:static final int x=10;則預設就是10.
(3)解析:這一階段的任務就是把常量池中的符號引用轉換為直接引用,說白了就是jvm會將所有的類或介面名、欄位名、方法名轉換為具體的記憶體地址。
3.初始化
初始化這個階段就是將靜態變數(類變數)賦值的過程,即只有static修飾的才能被初始化,執行的順序就是:父類靜態域或著靜態程式碼塊,然後是子類靜態域或者子類靜態程式碼塊(靜態程式碼塊先被載入,然後再是靜態屬性)
4.使用
在類的使用過程中依然存在以下三步:
(1)物件例項化:就是執行類中建構函式的內容,如果該類存在父類JVM會通過顯示或者隱示的方式先執行父類的建構函式,在堆記憶體中為父類的例項變數開闢空間,並賦予預設的初始值,然後在根據建構函式的程式碼內容將真正的值賦予例項變數本身,然後,引用變數獲取物件的首地址,通過操作物件來呼叫例項變數和方法
(2)垃圾收集:當物件不再被引用的時候,就會被虛擬機器標上特別的垃圾記號,在堆中等待GC回收
(3)物件的終結:物件被GC回收後,物件就不再存在,物件的生命也就走到了盡頭
5.類解除安裝
類解除安裝即類的生命週期走到了最後一步,程式中不再有該類的引用,該類也就會被JVM執行垃圾回收,從此生命結束…
程式碼示例:
package com.etc.test;
class
A{
static
int
a;
//類變數
String name;
int
id;
//靜態程式碼塊
static
{
a=10;
System.
out
.println(
"這是父類的靜態程式碼塊"
+a);
}
//構造程式碼塊
{
id=11;
System.
out
.println(
"這是父類的構造程式碼塊id:"
+id);
}
A(){
System.
out
.println(
"這是父類的無參建構函式"
);
}
A(String name){
System.
out
.println(
"這是父類的name"
+name);
}
}
class
B extends A{
String name;
static
int
b;
static
{
b=12;
System.
out
.println(
"這是子類的靜態程式碼塊"
+b);
}
B(String name) {
super();
this
.name = name;
System.
out
.println(
"這是子類的name:"
+name);
}
}
public
class
Test666 {
public
static
void
main(String[] args) {
B bb=
new
B(
"GG"
);
}
}
靜態程式碼在類的初始化階段被初始化。
非靜態程式碼則在類的使用階段(也就是例項化一個類的時候)才會被初始化。
- 靜態變數
- 可以將靜態變數理解為類變數(與物件無關),而例項變數則屬於一個特定的物件。
靜態變數有兩種情況:
- 靜態變數是基本資料型別,這種情況下在類的外部不必建立該類的例項就可以直接使用
- 靜態變數是一個引用。這種情況比較特殊,主要問題是由於靜態變數是一個物件的引用,那麼必須初始化這個物件之後才能將引用指向它。
- 因此如果要把一個引用定義成static的,就必須在定義的時候就對其物件進行初始化。
- public class TestForStaticObject{
- static testObject o = new testObject (); //定義一個靜態變數並例項化
- public static void main(String args[]){
- //在main中直接以“類名.靜態變數名.方法名”的形式使用testObject的方法
- }
- }
- 靜態方法
與類變數不同,方法(靜態方法與例項方法)在記憶體中只有一份,無論該類有多少個例項,都共用一個方法。
靜態方法與例項方法的不同主要有:
- 靜態方法可以直接使用,而例項方法必須在類例項化之後通過物件來呼叫。
- 在外部呼叫靜態方法時,可以使用“類名.方法名”或者“物件名.方法名”的形式。
- 例項方法只能使用這種方式物件名.方法名。
- 靜態方法只允許訪問靜態成員。而例項方法中可以訪問靜態成員和例項成員。
- 靜態方法中不能使用this(因為this是與例項相關的)。
- 靜態程式碼塊
在java類中,可以將某一塊程式碼宣告為靜態的。
- static {
- //靜態程式碼塊中的語句
- }
靜態程式碼塊主要用於類的初始化。它只執行一次,並且在同屬於一個類的main函式之前執行。
靜態程式碼塊的特點主要有:
- 靜態程式碼塊會在類被載入時自動執行。
- 靜態程式碼塊只能定義在類裡面,不能定義在方法裡面。
- 靜態程式碼塊裡的變數都是區域性變數,只在塊內有效。
- 一個類中可以定義多個靜態程式碼塊,按順序執行。
- 靜態程式碼塊只能訪問類的靜態成員,而不允許訪問例項成員。
靜態程式碼塊和靜態函式的區別
java 靜態程式碼塊:
一般情況下,如果有些程式碼必須在專案啟動前就執行的時候,需要使用靜態程式碼塊,這種程式碼是主動執行的,它只執行一次,並且在同屬於一個類的main函式之前執行。
靜態函式:
需要在專案啟動的時候就初始化,在不建立物件的情況下,其他程式來呼叫的時候,需要使用靜態方法,這種程式碼是被動執行的.
注意:
(1)靜態變數是屬於整個類的變數而不是屬於某個物件的。注意不能把任何方法體內的變數宣告為靜態,例如:
fun()
{<