-------android培訓、java培訓、期待與您交流! ----------
本日誌doc文檔下載
一、static關鍵字
1、用法
Static是一個修飾符,用於修飾成員,包括成員變量和成員函數。當成員被靜態修飾後,就多了一種調用方式,除了可以被對象調用外,還可以直接被類名調用。
2、特點
2.1 隨着類的加載而加載,也就是說靜態會隨着類的消失而消失,說明它的生命週期最長。
2.2 優先於對象存在:靜態是先存在的,對象是後存在的。
2.3 被所有對象共享
2.4 可以直接被類名所調用
3、實例變量和類變量的區別
3.1 存放位置
類變量隨着類的加載而存在與方法區中
實例變量隨着對象的建立而存在於堆內存中
3.2 生命週期
類變量生命週期最長,隨着類的消失而消失
實例變量生命週期隨着對象的消失而消失
4、靜態使用注意事項
4.1 靜態方法只能訪問靜態成員
非靜態方法既可以訪問靜態也可以訪問非靜態
4.2 靜態方法中不可以定義this,super關鍵字
因爲靜態優先於對象存在。所以靜態方法中不可以出現this
5、靜態的利與弊
5.1 利處:對對象的共享數據進行單獨空間的存儲,節省空間;沒有必要爲每一個對象都存儲一份,可以直接被類名調用。
5.2 弊處:生命週期過長,訪問出現侷限性(靜態雖好,只能訪問靜態)
二、Main函數詳解
主函數:一個特殊的函數,作爲程序的入口,可以被JVM調用。
主函數的定義:
public:代表着該函數訪問權限是最大的
static:代表主函數隨着類的加載就已經存在了
void:主函數沒有具體的返回值
main:不是關鍵字,但是是一個特殊的單詞,可以被JVM識別
(String [] args ):函數的參數,參數類型是一個字符串類型的數組。
總而言之:主函數是固定格式的,可以被JVM識別。JVM在調用主函數時,傳入的是new String[0]
代碼段一:
public class TestMain { public static void main(String[] args) { System.out.println("這裏是可以被JVM識別的主函數格式"); } public static void main(int args) { System.out.println("main並不是一個關鍵字,但是是一個特殊的單詞,可以被JVM識別"); } public static void main(String args) { System.out.println("名字爲main的方法重載形式"); } }
代碼段二:
public class TestMain02 { public static void main(String[] args) { System.out.println("主函數中參數長度:" + args.length); for (int i = 0; i < args.length; i++) { System.out.println(args[i]); } } }
運行結果如下所示
三、什麼時候使用靜態
因爲靜態修飾的內容有成員變量和函數,所以從兩方面下手:
什麼時候定義靜態變量(類變量)?
當對象出現共享數據時,該數據被靜態所修飾。
對象中的特有數據要定義成非靜態類型,存在與堆內存中。
什麼時候定義靜態函數?
當功能內部沒有訪問到非靜態數據(對象的特有數據),那麼可以將該功能定義成靜態的。
四、靜態的應用
每一個應用程序中都有共性的功能,可以將這些功能進行抽取,獨立封裝,以便複用。
五、製作程序的說明書
Java的說明書通過文檔註釋類完成。
代碼塊一
/** * 這是一個可以對數組進行操作的工具類,該類中提供了獲取最值的功能 * * @author LeeYou * @version v1.0 */ public class ArrayTool { private ArrayTool() { } /** * 獲取一個整型數組中的最大值 * * @param arr 接收一個int類型的數組 * @return 會返回一個該數組中的最大值 */ public static int getMax(int[] arr) { int max = 0; for (int i = 1; i < arr.length; i++) { if (arr[i] > arr[max]) { max = i; } } return arr[max]; } /** * 獲取一個整型數組中的最小值 * @param arr 接收一個int類型的數組 * @return 會返回一個該數組中最大值 */ public static int getMin(int[] arr) { int min = 0; for (int i = 1; i < arr.length; i++) { if (arr[i] < arr[min]) { min = i; } } return arr[min]; } }
利用控制檯運行命令如下:
生成的API截圖如下:
6、靜態代碼塊
格式:
Static { 靜態代碼塊中的執行語句 }
特點:隨着類的加載而執行,只執行一次,用於給類進行初始化
代碼塊一:
class StaticCode { StaticCode() { System.out.println("無參構造函數運行了..."); } static { System.out.println("靜態代碼塊運行了..."); } { System.out.println("構造代碼塊運行了..."); } StaticCode(int x) { System.out.println("帶參數的構造函數執行了..." + "傳入整形參數:" + x); } public static void show() { System.out.println("靜態方法運行了..."); } } public class StaticCodeDemo { static { System.out.println("主類的靜態代碼快運行了..."); } public static void main(String[] args) { new StaticCode(8); } }
運行結果如下所示:
7、對象建立和調用過程
BubbleSort bs = new BubbleSort();
這句代碼做了一些什麼事情?
1,因爲new用到了BubbleSort.class,所以會先找到BubbleSort.class文件並加載到內存中。
2,執行該類中的static代碼塊,如果有的話,給BubbleSort.class類執行初始化。
3,在堆內存中開闢空間,分配內存地址。
4,在堆內存中建立對象的特有屬性,並進行默認的初始化。
5,對屬性進行顯示初始化。
6,對對象進行構造代碼塊初始化。
7,對對象進行對應的構造函數初始化。
8,將內存地址賦給棧內存中的bs變量。
理解這段執行順序比較繞,但是很重要,理解創建一個對象在底層到底是怎樣被創建被賦值的有助於以後深入JVM的學習。
關於帶靜態屬性和方法的類加載時,內存中的分配情況見下圖:
8、單例設計模式
設計模式:解決某一類問題最行之有效的方法
單例設計模式:解決一個類在內存中只存在一個對象
想要保證對象的唯一:
1,爲了避免其他程序過多的建立該類對象,先禁止其他程序建立該類對象
2,爲了讓其他程序可以訪問到該類對象,在本類中自定義一個對象
3,爲了方便其他程序對自定義對象的訪問
這三步怎麼用代碼體現呢?
1,將構造函數私有化
2,在類中創建一個本類對象
3,提供一個方法可以獲取到該對象
餓漢式單例模式代碼塊:
/** * 這個是先初始化對象,稱爲:餓漢式 * Single_LazyMan 類一加載進內存,就已經創建好了對象 * 實際開發中一般採用這種方式 * @author LeeYou * */ public class Single_HungryMan { private static Single_HungryMan s = new Single_HungryMan(); private Single_HungryMan() { } public static Single_HungryMan getInstance() { return s; } }
懶漢式單例模式代碼塊:
/** * 對象是方法被調用時,才初始化,也叫做對象的延時加載。稱爲:懶漢式 Single_LazyMan * 類加載進內存,對象還沒有存在,只有調用了getInstance()方法時,才建立對象 但是這種方式在"////"處存在問題,解決辦法如下 public static Single_LazyMan getInstance() { if (s == null) { synchronized (Single_LazyMan.class) { if (s == null) { s = new Single_LazyMan(); } } } return s; } * @author LeeYou * */ public class Single_LazyMan { private static Single_LazyMan s = null; private Single_LazyMan() { } public static Single_LazyMan getInstance() { if (s == null) //// s = new Single_LazyMan(); return s; } }