一般在進行分析的時候,會從三個方面進行分析:類、方法(構造方法、成員方法)、變量(成員變量(靜態變量、實例變量)、局部變量)。
一、static修飾符:
被static修飾的變量和方法,被類的所有實例所共享
。加載類時只分配一次內存。
- 靜態變量:可以直接通過類名來訪問 Person.a;
- 靜態方法:可以直接通過類名來訪問 Person.say();靜態方法內,可以訪問靜態變量,但是
不能使用this關鍵字
且不能訪問實例變量
,因爲被所有實例所共有,無法判斷屬於哪個實例對象 - 靜態代碼塊:java虛擬機在加載類時就執行代碼塊
二、final修飾符:
有final修飾表示最終(不可再修改)
的意思:
- final類:不能被繼承(即沒有子類);
- final方法:不能被子類的方法覆蓋(final不用來修飾構造方法,父類與子類之間的構造方法不存在覆蓋關係,final修飾是沒有意義的);
- final修飾的變量:即常量,常量只能被賦值一次,之後不能改變。(以下
靜態常量
屬於編譯時常量
(final static int a=2*3;在編譯的時就能計算出具體的值),在編譯的時候將這個值就放入到常量池中,a被訪問時類是不會被初始化的(這是類的被動使用
)。訪問類的靜態變量或靜態方法的時候類會被初始化(這是類的主動使用
)。但只有static修飾的常量,只會在類初始化的時候纔會賦值)。具體細節請參考“類的生命週期”
---加載(堆區、方法區)--連接(驗證、準備(靜態變量分配內存、設置默認初始值爲0)、解析(符號引用替換爲直接引用,即指針指向方法區的內存位置))--初始化(程序對類或接口主動使用
的時候纔會被初始化)。
三、類的初始化時機:
類的初始化
即java虛擬機爲類的static靜態變量
賦予初始值(這和準備階段設置默認初始值爲0是不一樣的)。只有類的主動使用纔會初始化類
。
1.類的主動使用(6種):
- 創建類的實例:用new語句創建實例 Person ps=new Person();
-
調用類的靜態變量或對靜態變量賦值:
public class Person{ static int a=2*3; //這和final static int a=2*3;是有區別的 static{ //Java在定義一個類的時候裏面只能放方法和屬性,這是規定死了的。System.out.println()是在調用一個叫println的函數,這裏是函數的調用而不是類裏面定義一個函數。所以需要用static代碼塊 System.out.println("init Person"); //static聲明的靜態代碼塊,使得類在初始化的時候會被調用而不需要創建實例對象。它這時候就不在任何一個方法中。 } } 調用的時候寫: System.out.println("a="+Person.a); //這樣就可以在不new一個Person實例的情況下,來初始化Person類了。
- 調用類的靜態方法;
- 調用java API中的反射方法:Class.forName("Person");
- 初始化子類的時候會先初始化父類(但"父類"是接口的時候,不會先初始化它所實現的接口的,只有在程序在使用接口的靜態變量時纔會使靜態接口初始化)
- java虛擬機啓動時被標明爲啓動類的類
2.類的被使用:
-
final類型的靜態變量在編譯的時候能計算出值(即編譯時常量,在編譯的時候將這個值就放入到常量池中了):
注: final類型的靜態變量在編譯的時候不能計算出變量的值的時候是會被初始化的``` final static int a=2*3; //變量a是編譯時常量 final static int a=(int)Math.random(); //變量a不是是編譯時常量 ```
- "父類"是接口的時候,不會先初始化它所實現的接口的,只有在程序在使用接口的靜態變量時纔會使靜態接口初始化
- ClassLoader類的loadClass("Person")方法的時候,只是對類的加載,不是初始化。Class.forName("Person");纔會初始化