static關鍵字
靜態:static
用法:是一個修飾符,用於修飾成員(成員變量,成員函數)(只能修飾成員,不能修飾局部)
當成員被靜態修飾後,就多了一個調用方式,除了可以被對象調用外,
還可以直接被類名調用。類名.靜態成員
static的特點:
1.隨着類的加載而加載
也就是說,靜態會隨着類的消失而消失。說明它的生命週期最長
2.優先於對象存在
所以纔會直接用類名調用,當時對象還不存在
明確一點:靜態是先存在的,對象是後存在的
3.被所有對象所共享
4.可以直接被類名所調用
class person
{
String name;//成員變量,實例變量。(對象的變量)對象存在才存在
static String country = "CN";//靜態的成員變量,類變量。類存在就存在
}
class staticDemo
{
public static void main(String[] args)
{
System.out.println(person.country);//類名.靜態成員
}
}
實例變量和類變量的區別
1.存放位置
類變量隨着類的加載而存在於方法區中。
實例變量隨着對象的建立而存在於堆內存中。
2.生命週期
類變量生命週期最長,隨着類的消失而消失
實例變量生命週期隨着對象的消失而消失
靜態的使用注意事項:
1.靜態方法只能訪問靜態成員,方法
非靜態方法既可以訪問靜態,也可以訪問非靜態
2.靜態方法中不可以定義this,super關鍵字
因爲靜態優先於對象存在,所以靜態方法中不可以出現this
3.主函數是靜態的
靜態有利有弊
利:對對象的共享數據進行單獨空間的存儲,節省空間。沒有必要每個對象都存儲一份
可以直接被類名調用
弊:生命週期過長
訪問出現侷限性(靜態雖好,只能訪問靜態)
main函數
public static void main(String[] args) 虛擬機只要這個主函數
主函數:是一個特別的函數,作爲程序的入口,可以被jvm調用
它是程序的起始點
主函數的定義:
public:代表着該函數訪問權限是最大的
static:代表主函數隨着類的加載就已經存在了
void:主函數沒有具體的返回值
main:不是關鍵字,但是是一個特殊的單詞,可以被jvm識別
(String[] args):函數的參數,參數類型是一個數組,該數組中的元素是字符串。也就是字符串類型的數組。
主函數是固定格式的:jvm識別
jvm在調用主函數時,傳入的是new String[0];
class mainDemo
{
public static void main(int x)//函數名相同,參數列表不一樣 重載
{
}
public static void main(String[] args,int x)
{
System.out.println();
}
public static void main(String[] args){}
}
什麼時候使用靜態?
要從兩方面下手:
因爲靜態修飾的內容有成員變量和成員函數
什麼時候定義靜態變量(類變量)呢?
當對象中出現共享數據時,該數據被靜態修飾。
對象中的特有數據要定義成非靜態存在於堆內存中
什麼時候定義靜態函數呢?
當功能內部沒有訪問到非靜態數據(對象的特有數據),
那麼該功能可以定義成靜態的。
靜態的應用
每一個應用程序中都有共性的功能,
可以將這些功能進行抽取,獨立封裝
以便複用。
雖然可以通過建立ArrayTool的對象使用這些工具方法,對數組進行操作
發現了問題:
1,對象是用於封裝數據的,可是ArrayTool對象並沒有封裝特有數據
2,操作數組的每一個方法都沒有用到ArrayTool對象中的特有數據
這時就考慮,讓程序更嚴謹,是不需要對象的
可以將ArrayTool中的方法都定義成靜態的,直接通過類名調用即可
將方法都靜態後,可以方便使用,但是該類還是可以被其他程序建立對象的
爲了更加嚴謹,強制讓該類不能建立對象
可以通過將構造函數私有化完成。
接下來,將ArrayTool.class文件發送給其他人,其他人只要將該文件設置到classpath路徑下,就可以使用該工具類
但是很遺憾,該類中到底定義了多少個方法,對方卻不清楚。因爲該類並沒有使用說明書。
開始製作程序的說明書。java的說明書通過文檔註釋來完成。
public class ArrayTool
{
/**
空參數構造函數。
*/
private ArrayTool(){} //私有化
/**
獲取一個整型數組的最大值
@param arr 接受一個int類型的數組
@return 會返回一個該數組的最大值
*/
public static int getMax(int[] arr)
{
int max = 0;
for(int x= 1;x<arr.length;x++)
{
if(arr[x]>arr[max])
max = x;
}
return arr[max];
}
/**
獲取一個整型數組的最小值
@param arr 接受一個int類型的數組
@return 會返回一個該數組的最小值
*/
public static int getMin(int[] arr)
{
int min = 0;
for(int x=1;x<arr.length;x++)
{
if(arr[x]<arr[min])
min = x;
}
return arr[min];
}
/**
給int數組進行選擇排序。
@param arr 接受一個int類型的數組
*/
public static void selectSort(int[] arr)
{
for (int x=0;x<arr.length;x++)
{
for(int y=x+1;y<arr.length;y++)
{
if(arr[x]>arr[y])
{
swap(arr,x,y);
}
}
}
}
/**
給int數組進行冒泡排序。
@param arr 接受一個int類型的數組
*/
public static void bubbleSort(int[] arr)
{
for(int x=0;x<arr.length;x++)
{
for(int y=0;y<arr.length-x-1;y++)
{
if(arr[y]>arr[y+1])
{
swap(arr,y,y+1);
}
}
}
}
/**
給數組中的元素進行位置的置換
@param arr 接受一個int類型的數組
@param a 要置換的位置
@param b 要置換的位置
*/
private static void swap(int[] arr,int a,int b)
{
int temp = arr[a];
arr[a] = arr[b];
arr[b] = temp;
}
/**
用於打印數組中的元素,打印形式是:[elemet1 ,elemet2 , ...]
*/
public static void printArray(int[] arr)
{
System.out.print("[");
for(int x=0;x<arr.length;x++)
{
if(x!=arr.length-1)
System.out.print(arr[x]+",");
else
System.out.println(arr[x]+"]");
}
}
}
/*
class Demo
{
public static void main(String[] args)
{
//int[] arr = {3,4,1,8};
int[] arr = {3,4,19,8};
int max = getMax(arr);
System.out.println("max="+max);
}
public static int getMax(int[] arr)
{
int max = 0;
for(int x= 1;x<arr.length;x++)
{
if(arr[x]>arr[max])
max = x;
}
return arr[max];
}
}
一個類中默認會有一個空參數的構造函數
這個默認的構造函數的權限和所屬類一致
這個類被public修飾,那麼默認的構造函數也帶public修飾符
如果類沒有被public修飾,那麼默認的構造函數也沒有被public修飾。
靜態代碼塊
靜態代碼塊
格式:
static
{
靜態代碼塊中的執行語句。
}
特點:隨着類的加載而執行,只執行一次,並優先於主函數。
用於給類進行初始化
class StaticCode
{
static
{
System.out.println("a");
}
}
class StaticCodeDemo
{
static
{
System.out.println("b");
}
public static void main(String[] args)
{
new StaticCode();
new StaticCode();//第二次不執行
System.out.println("over");
}
static
{
System.out.println("c");
}
}
打印結果:b c a over
person p = new person(“zhangsan”,20);
這句話都做了什麼事情?
1,因爲new用到了person.class所以會先找到person.class文件並加載到內存中。
2,執行該類中的static代碼塊(如果有的話),給person.class類進行初始化。
3,在堆內存中開闢出空間,分配內存地址
4,在堆內存中建立對象的特有屬性,並進行默認初始化
5,對屬性進行顯示初始化
6,對對象進行構造代碼塊初始化
7,對對象進行對應的構造函數初始化
8,將內存地址賦給內存中的P變量
初始化順序:
靜態代碼塊初始化>默認初始化>顯示初始化>構造代碼塊初始化>構造函數初始化
單例設計模式
設計模式:解決某一類問題最行之有效的方法
java中有23種設計模式:其中一種
單例設計模式:解決一個類在內存中只存在一個對象
想要保證對象唯一。
1,爲了避免其他程序過多建立該類對象。先禁止其他程序建立該類對象
2,還爲了讓其他程序可以訪問到該類對象,只好在本類中,自定義一個對象
3,爲了方便其他程序對自定義對象的訪問,可以對外提供一些訪問方式
這三部用代碼體現:
1,將構造函數私有化
2,在類中創建一個本類對象
3,提供一個方法可以獲取到該對象
對於事物該怎麼描述,還怎麼描述
當需要將該事物的對象保證在內存中唯一時,就將以上的三步加上即可。
class Single
{
private Single(){} //1
private static Single s = new Single(); //2
public static Single getInstance() //3
{
return s;
}
}
class SingleDemo
{
public static void main(String[] args)
{
Single ss = Single.getInstance();
}
}
這個是先初始化對象。
稱爲:餓漢式。
Single類一進內存,就已經創建好了對象
開發一般用餓漢式
class Single
{
private static Single s = new Single();
private Single(){}
public static Single getInstance()
{
return s;
}
}
對象是方法被調用時,才初始化,也叫做對象的延時加載。
稱爲:懶漢式。
Single類進內存,對象還沒有存在,只有調用了getInstance方法時,才建立對象。
class Single
{
private static Single s = null;
private Single(){}
public static Single getInstance()
{
if(s==null)
s = new Single();
return s;
}
}
原則:定義單例,建議使用餓漢式