張會(huì)
摘要: 介紹了static關(guān)鍵詞定義Java類變量,類方法及初始化器,static在main()方法和單例設(shè)計(jì)模式中的應(yīng)用,使Java編程人員對(duì)static關(guān)鍵詞的使用有更深入的理解,并能靈活應(yīng)用于Java編程中。
關(guān)鍵詞:static;單例設(shè)計(jì)模式;類變量;類方法
中圖分類號(hào):TP393 文獻(xiàn)標(biāo)識(shí)碼:A 文章編號(hào):1009-3044(2017)33-0102-02
在Java中,static關(guān)鍵詞可用來修飾類的成員變量,成員方法及代碼塊,用static關(guān)鍵詞修飾的類變量和類方法存儲(chǔ)于方法區(qū),而方法區(qū)中數(shù)據(jù)和方法只存在一份,因此static修飾的成員變量和成員方法能被所有對(duì)象共享。類中static成員是隨著類加載器加載類的時(shí)候加載一次,因此static成員與類的生命周期一致,所以類中的static成員可以通過類名直接引用。
1 static修飾類成員
類成員是指用static修飾的變量和方法。由static修飾定義的靜態(tài)變量和靜態(tài)方法,既可通過類的實(shí)例對(duì)象引用,也可通過類名引用,正是因?yàn)閟tatic成員可以通過類名直接引用,因此把用static修飾的成員變量和成員方法稱為類變量和類方法。
1.1 類變量
類變量也叫靜態(tài)變量,也就是在類中加了static修飾的成員變量,類變量不專屬于任何一個(gè)具體的對(duì)象,被所有對(duì)象共用。通常將類的共享數(shù)據(jù)用static定義成類變量,而其他屬性定義為實(shí)例變量,把類中定義時(shí)沒加static的成員變量稱為實(shí)例變量。類變量與實(shí)例變量的區(qū)別有:
1) 類變量是隨類的加載而存在,隨著類的消失而消失,其與類的生命周期相同;而實(shí)例變量是隨著對(duì)象的創(chuàng)建而存在,隨著對(duì)象被JVM(Java虛擬機(jī))垃圾回收器回收而消失;
2) 類變量是存儲(chǔ)在方法區(qū)內(nèi)存中,而且只存在一份數(shù)據(jù),用于所有對(duì)象共享;實(shí)例變量是存儲(chǔ)在堆內(nèi)存中,有n個(gè)對(duì)象就有n份數(shù)據(jù)。
3) 類變量共享數(shù)據(jù)給所有的對(duì)象使用,可以被類名直接訪問;實(shí)例變量是在對(duì)象實(shí)例化后才分配堆空間,故不能被類名直接訪問,只能使用對(duì)象進(jìn)行訪問。
public class Student1 {
String name;
int num;
static int count;
public Student1(String name, int num) {
this.name = name;
this.num = num;
count++;}
public static void main(String[] args) {
Student1 stu1 = new Student1("張麗", 101);
Student1 stu2 = new Student1("孫力", 102);
System.out.println("創(chuàng)建的學(xué)生對(duì)象個(gè)數(shù)有:" + Student1.count+"名");}}
運(yùn)行結(jié)果:創(chuàng)建的學(xué)生對(duì)象個(gè)數(shù)有:2名
在Student1類中,用static定義了count類變量,該變量被Student1創(chuàng)建的所有對(duì)象共同使用。在Student1類的構(gòu)造函數(shù)中的count++實(shí)現(xiàn)了,每創(chuàng)建一個(gè)Student1對(duì)象,共享類變量count的值會(huì)自動(dòng)加1,從而實(shí)現(xiàn)了用一個(gè)共享的類變量來統(tǒng)計(jì)所實(shí)例化的學(xué)生人數(shù)。
1.2 類方法
類方法是指類中的方法前面加了static進(jìn)行修飾的成員方法。類方法的調(diào)用與類變量的使用相似,可以通過類名進(jìn)行調(diào)用。在static定義的類方法中,只能直接訪問類中的類變量和類方法。類方法在類被加載到內(nèi)存時(shí)就分配了入口地址,實(shí)例方法(類中定義時(shí)沒加static 的成員方法)是在對(duì)象實(shí)例化后才分配入口地址或?qū)嵗兞康亩芽臻g,因此類方法中不能直接訪問實(shí)例變量或者實(shí)例方法,另外在類方法中也不能使用代表對(duì)象的this和super關(guān)鍵詞,但是在類方法中可以通過實(shí)例化對(duì)象去引用類的實(shí)例成員。
public class Student2 {
String name;
int num;
double score;
static double sum;
static int count;
public Student2(String name,double score){
this.name=name;
this.score=score;
sum+=score;
count++;}
public static double average(){
return sum/count;}
public static void main(String[] args) {
Student2 stu[]={new Student2("張麗",80),new Student2("孫力",90)};
System.out.println("average:"+Student2.average());}}
運(yùn)行結(jié)果:average:85
以上Student2類中定義了兩個(gè)類變量sum和count,sum用來存放創(chuàng)建的所有學(xué)生對(duì)象的總成績(jī),count用來統(tǒng)計(jì)創(chuàng)建學(xué)生對(duì)象個(gè)數(shù)。在構(gòu)造函數(shù)中使用sum+=score;count++;語句實(shí)現(xiàn)在新建對(duì)象時(shí)累加新建學(xué)生對(duì)象的成績(jī)及統(tǒng)計(jì)新建學(xué)生對(duì)象人數(shù)。同時(shí)在類中定義了一個(gè)靜態(tài)方法static double average()用于求所創(chuàng)建的所有學(xué)生的平均成績(jī),由于所計(jì)算出的平均成績(jī)不屬于某一個(gè)對(duì)象的,而是屬于類,通過類去調(diào)用更合適,所以將此方法定義成類方法。
通常當(dāng)一個(gè)函數(shù)沒有直接訪問實(shí)例成員而只是直接訪問類成員時(shí),該函數(shù)可以使用static定義成類方法。 在實(shí)際的應(yīng)用中static方法的定義多用于工具類中方法的定義。如Math,Arrays等工具類中的方法都是static,其中的類方法都是通過類進(jìn)行調(diào)用。
1.3 初始化器
初始化器是一段不在方法之內(nèi)的程序代碼,這段代碼用{}包圍起來。初始化器分成靜態(tài)和非靜態(tài)初始化器。非靜態(tài)初始化器,在實(shí)例化對(duì)象時(shí)執(zhí)行,一般用于初始化實(shí)例變量,靜態(tài)初始化器僅在類加載入內(nèi)存時(shí)執(zhí)行一次,一般用于初始化類變量[1]。
下面代碼中用于實(shí)現(xiàn)對(duì)新創(chuàng)建的學(xué)生進(jìn)行學(xué)號(hào)自動(dòng)連續(xù)編號(hào)并計(jì)數(shù)功能。其中靜態(tài)初始化器實(shí)現(xiàn)對(duì)count(用于計(jì)數(shù)),nexNum(用于學(xué)號(hào)遞增)和year(表示入學(xué)年份)三個(gè)類變量進(jìn)行初始化。而非靜態(tài)代碼塊實(shí)現(xiàn)對(duì)新生成的學(xué)生學(xué)號(hào)進(jìn)行連續(xù)編號(hào)并統(tǒng)計(jì)創(chuàng)建學(xué)生的人數(shù)。
public class Student {
private String name;
private int num;
private static int nextNum;
private static int count;
private static int year;
static { //靜態(tài)初始化器 類被加載時(shí)執(zhí)行,僅被執(zhí)行一次
count=0; //學(xué)生人數(shù)計(jì)數(shù)器初始化
nextNum=10804000; //學(xué)號(hào)自增變量初始化
year =2017; //入學(xué)年份初始化
}
{//非靜態(tài)初始化器:每實(shí)例化一個(gè)對(duì)象時(shí),都會(huì)被執(zhí)行
count++;
nextNum++;
num=nextNum; } //為每個(gè)新建學(xué)生學(xué)號(hào)使用nextNum的值進(jìn)行連續(xù)編號(hào)
public Student(String name){
this.name=name;}
public String toString() {
return "name=" + name + " num="+year+num;}
public static void main(String[] args) {
Student stu[]={new Student("張麗"),
new Student("孫力"),
new Student("王琴")};
for(int i=0;i System.out.println(stu[i]);}} 運(yùn)行結(jié)果:name=張麗 num=201710804001 name=孫力 num=201710804002 name=王琴 num=201710804003 2 static關(guān)鍵詞在單例設(shè)計(jì)模式中的應(yīng)用 Java中單例設(shè)計(jì)模式是指一個(gè)類有且僅有一個(gè)實(shí)例,并且是在類中生成唯一實(shí)例對(duì)象。單例設(shè)計(jì)模式通過定義private的構(gòu)造函數(shù)來阻止在類外生成實(shí)例對(duì)象,從而限制了對(duì)象的實(shí)例化只能在類中實(shí)現(xiàn)。單例設(shè)計(jì)模式使用了工廠方法來限制實(shí)例化過程,這個(gè)工廠方法即是靜態(tài)方法(類方法)[2]。 下面代碼是餓漢單例設(shè)計(jì)模式: public class Single{ //聲明本類的私有引用類型變量,并且使用該變量指向本類實(shí)例化對(duì)象 private static Single s = new Single(); //私有化構(gòu)造函數(shù),無法在類外實(shí)例化對(duì)象 private Single(){} //提供一個(gè)公共靜態(tài)的方法(類方法)獲取本類的對(duì)象 public static Single getInstance(){ return s;}} 在Single類中,定義了一個(gè)Single類的靜態(tài)引用變量s,同時(shí)通過new進(jìn)行對(duì)象的實(shí)例化,因?yàn)樵擃惓蓡T變量s使用了static進(jìn)行修飾,所以在類加載入內(nèi)存時(shí)就會(huì)生成實(shí)例化對(duì)象。由于類中定義了一個(gè)private的構(gòu)造函數(shù),因此在類外不能通過Single類實(shí)例化任何Single對(duì)象,同時(shí)由于構(gòu)造函數(shù)是私有的,所以該類是不能被繼承,因此也不能通過該類的子類生成該類對(duì)象,從而保證該類中s對(duì)象的唯一性。由于在類外無法生成對(duì)象,而又需要使用該類提供的私有類對(duì)象,故該類提供了一個(gè)公用的靜態(tài)(static)方法getInstance()來獲得類中生成的唯一實(shí)例對(duì)象,并且該方法只能通過類名調(diào)用。由于類中的唯一對(duì)象在類被加載到內(nèi)存時(shí)就生成,故將此種生成方式稱為餓漢模式,此種模式生成的實(shí)例對(duì)象是線程安全的。 單例設(shè)計(jì)模式的核心作用就是保證一個(gè)類有且只有一個(gè)實(shí)例,通過提供一個(gè)全局訪問點(diǎn)來訪問這個(gè)實(shí)例對(duì)象[3]。此訪問點(diǎn)即是類中提供的公用的static方法來實(shí)現(xiàn)。由于單例設(shè)計(jì)模式確保類只生成一個(gè)實(shí)例對(duì)象,在實(shí)例化之后向整個(gè)系統(tǒng)提供這個(gè)實(shí)例,所以在計(jì)算機(jī)系統(tǒng)中,線程池、緩存、日志對(duì)象、對(duì)話框、打印機(jī)、顯卡的驅(qū)動(dòng)程序經(jīng)常被設(shè)計(jì)成單例[4]。 常見的單例設(shè)計(jì)模式有:餓漢式、懶漢式、雙重檢測(cè)鎖式、靜態(tài)內(nèi)部類式、枚舉單例式,而本文是為了綜合介紹static在java程序設(shè)計(jì)中的應(yīng)用,故其他單例模式在此不進(jìn)行介紹。 3 static 關(guān)鍵詞在main()中的應(yīng)用 一個(gè)Java Application執(zhí)行的入口函數(shù)是main()函數(shù)。main()函數(shù)的首部聲明形如:public static void main(String args[]), main()函數(shù)聲明為static類型,是為了讓Java虛擬機(jī)調(diào)用main()函數(shù)時(shí)更加方便,不需要通過實(shí)例化進(jìn)行調(diào)用,而是通過Java虛擬機(jī)直接調(diào)用。 4 結(jié)束語 本文介紹了static修飾的成員變量、成員方法,用于實(shí)現(xiàn)對(duì)所有對(duì)象共享;static修飾代碼塊,實(shí)現(xiàn)對(duì)類變量進(jìn)行初始化,從而構(gòu)成類初始化器,在文中示例代碼里通過static初始化器完成了對(duì)新建對(duì)象計(jì)數(shù),自動(dòng)編號(hào)等功能。另外還介紹了static用于單例設(shè)計(jì)模式生成類的唯一實(shí)例及應(yīng)用于Java Application的執(zhí)行入口函數(shù)main()函數(shù)。通過對(duì)static在Java Application中應(yīng)用介紹,使Java程序員綜合了解static特性,并能靈活運(yùn)用于Java程序開發(fā)中。 參考文獻(xiàn): [1] 王振飛,孫嬡.Java語言程序設(shè)計(jì)[M].廣州:華南理工大學(xué)出版社,2015. [2] 鐘冠賢.Objective-C編程之道 iOS設(shè)計(jì)模式解析[M].北京:人民郵電出版社,2011:80. [3] 陳天超.單例設(shè)計(jì)模式研究[J].福建電腦,2016,32(8):14-15. [4] 夏浩波.單例模式的設(shè)計(jì)與應(yīng)用[J].電腦開發(fā)與應(yīng)用,2011,24(1):58-59. [5] 王麗麗.Java中的static關(guān)鍵詞詳解[J].學(xué)術(shù)探討,2010,20(10):270-272.