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