static各個語言運用

2puT發表於2016-07-13


像在VB,C#,C,C++,Java中我們可以看到static作為關鍵字和函式出現,在其他的高階計算機語言如FORTRAN、ALGOL、COBOL、BASIC、LISP、SNOBOL、PL/1、Pascal、PROLOG、Ada等語言中也是有出現的,只是有著不同的作用,對於其具體作用,讀者有需要的時候是可以具體查閱的。
中文名
static
分    類
關鍵字
舉    例
VB,C#,C,C++
來    自
高階計算機語言

C++中

編輯
C++與C#的static有兩種用法:程式導向程式設計中的static和物件導向程式設計中的static。前者應用於普通變數和函式,不涉及類;後者主要說明static在類中的作用。[1] 

程式導向

靜態全域性變數
全域性變數前,加上關鍵字static,該變數就被定義成為一個靜態全域性變數。我們先舉一個靜態全域性變數的例子,如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//Example1
#include<iostream>
usingnamespace std;
void fn();  //宣告函式
static int n;  //宣告靜態全域性變數
void main()
{
    n=20;  //為n賦初值
    printf("%d",n);//輸出n的值
    fn();  //呼叫fn函式
}
void fn()
{
    n++;  //n的值自加一(n=n+1)
    printf("%d",n);  //輸出n的值
}
靜態全域性變數有以下特點:
該變數在全域性資料區分配記憶體;
未經初始化的靜態全域性變數會被程式自動初始化為0(在函式體內宣告的自動變數的值是隨機的,除非它被顯式初始化,而在函式體外被宣告的自動變數也會被初始化為0);
靜態全域性變數在宣告它的整個檔案都是可見的,而在檔案之外是不可見的;
靜態變數都在全域性資料區分配記憶體,包括後面將要提到的靜態區域性變數。對於一個完整的程式,在記憶體中的分佈情況如下圖:
程式碼區 //low address全域性資料區堆區棧區 //high address
一般程式把新產生的動態資料存放在堆區,函式內部的自動變數存放在棧區。自動變數一般會隨著函式的退出而釋放空間,靜態資料(即使是函式內部的靜態區域性變數)也存放在全域性資料區。全域性資料區的資料並不會因為函式的退出而釋放空間。細心的讀者可能會發現,Example 1中的程式碼中將
static int n; //定義靜態全域性變數
改為
int n; //定義全域性變數
程式照樣正常執行。
的確,定義全域性變數就可以實現變數在檔案中的共享,但定義靜態全域性變數還有以下好處:
靜態全域性變數不能被其它檔案所用;
其它檔案中可以定義相同名字的變數,不會發生衝突;
您可以將上述示例程式碼改為如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//Example2
//File1第一個程式碼檔案的程式碼
#include<iostream.h>
void fn();  //宣告fn函式
static int n;  //定義靜態全域性變數
void main()
{
    n=20;
    cout<<n<<endl;
    fn();
}
//File2第二個程式碼檔案的程式碼
#include<iostream.h>
extern int n;
void fn()
{
    n++;
    printf("%d",n);
}
編譯並執行Example 2,您就會發現上述程式碼可以分別通過編譯,但執行時出現錯誤。試著將
static int n; //定義靜態全域性變數
改為
int n; //定義全域性變數
再次編譯執行程式,細心體會全域性變數和靜態全域性變數的區別。
注意:全域性變數和全域性靜態變數的區別
1)全域性變數是不顯式用static修飾的全域性變數,全域性變數預設是有外部連結性的,作用域是整個工程,在一個檔案內定義的全域性變數,在另一個檔案中,通過extern 全域性變數名的宣告,就可以使用全域性變數。
2)全域性靜態變數是顯式用static修飾的全域性變數,作用域是宣告此變數所在的檔案,其他的檔案即使用extern宣告也不能使用。
靜態區域性變數
區域性變數前,加上關鍵字static,該變數就被定義成為一個靜態區域性變數。
我們先舉一個靜態區域性變數的例子,如下
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//Example3
#include<iostream.h>
#include<stdio.h>
void fn();
void main()
{
    fn();
    fn();
    fn();
}
void fn()
{
    static int n=10;
    printf("%d",n);
    n++;
}
通常,在函式體內定義了一個變數,每當程式執行到該語句時都會給該區域性變數分配棧記憶體。但隨著程式退出函式體,系統就會收回棧記憶體,區域性變數也相應失效。
但有時候我們需要在兩次呼叫之間對變數的值進行儲存。通常的想法是定義一個全域性變數來實現。但這樣一來,變數已經不再屬於函式本身了,不再僅受函式的控制,給程式的維護帶來不便。
靜態區域性變數正好可以解決這個問題。靜態區域性變數儲存在全域性資料區,而不是儲存在棧中,每次的值保持到下一次呼叫,直到下次賦新值。
靜態區域性變數有以下特點:
該變數在全域性資料區分配記憶體;
靜態區域性變數在程式執行到該物件的宣告處時被首次初始化,即以後的函式呼叫不再進行初始化;
靜態區域性變數一般在宣告處初始化,如果沒有顯式初始化,會被程式自動初始化為0;
它始終駐留在全域性資料區,直到程式執行結束。但其作用域為區域性作用域,當定義它的函式或語句塊結束時,其作用域隨之結束;
靜態函式
在函式的返回型別前加上static關鍵字,函式即被定義為靜態函式。靜態函式與普通函式不同,它只能在宣告它的檔案當中可見,不能被其它檔案使用。
靜態函式的例子:
1
2
3
4
5
6
7
8
9
10
11
12
//Example4
#include<iostream.h>
static void fn();//宣告靜態函式
void main()
{
    fn();
}
void fn()//定義靜態函式
{
    intn=10;
    printf("%d",n);
}
定義靜態函式的好處:
靜態函式不能被其它檔案所用;
其它檔案中可以定義相同名字的函式,不會發生衝突;

物件導向

(類中的static關鍵字
靜態資料成員
在類內資料成員的宣告前加上關鍵字static,該資料成員就是類內的靜態資料成員。先舉一個靜態資料成員的例子。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
//Example5
#include<iostream.h>
class Myclass
{
    public:
        Myclass(int a,int b,int c);
        void GetSum();
    private:
        int a,b,c;
        static int Sum;//宣告靜態資料成員
};
int Myclass::Sum=0;//定義並初始化靜態資料成員
 
Myclass::Myclass(int a,int b,int c)
{
    this->a=a;
    this->b=b;
    this->c=c;
    Sum+=a+b+c;
}
void Myclass::GetSum()
{
    cout<<"Sum="<<Sum<<endl;
}
void main()
{
    Myclass M(1,2,3);
    M.GetSum();
    Myclass N(4,5,6);
    N.GetSum();
    M.GetSum();
}
可以看出,靜態資料成員有以下特點:
對於非靜態資料成員,每個類物件都有自己的拷貝。而靜態資料成員被當作是類的成員。無論這個類的物件被定義了多少個,靜態資料成員在程式中也只有一份拷貝,由該型別的所有物件共享訪問。也就是說,靜態資料成員是該類的所有物件所共有的。對該類的多個物件來說,靜態資料成員只分配一次記憶體,供所有物件共用。所以,靜態資料成員的值對每個物件都是一樣的,它的值可以更新;
靜態資料成員儲存在全域性資料區。靜態資料成員定義時要分配空間,所以不能在類宣告中定義。在Example 5中,語句int Myclass::Sum=0;是定義靜態資料成員;
靜態資料成員和普通資料成員一樣遵從public,protected,private訪問規則;
因為靜態資料成員在全域性資料區分配記憶體,屬於本類的所有物件共享,所以,它不屬於特定的類物件,在沒有產生類物件時其作用域就可見,即在沒有產生類的例項時,我們就可以操作它;
靜態資料成員初始化與一般資料成員初始化不同。靜態資料成員初始化的格式為:
<;資料型別><;類名>::<;靜態資料成員名>=<;值>
類的靜態資料成員有兩種訪問形式:
<;類物件名>.<;靜態資料成員名> 或 <;類型別名>::<;靜態資料成員名>
如果靜態資料成員的訪問許可權允許的話(即public的成員),可在程式中,按上述格式來引用靜態資料成員 ;
靜態資料成員主要用在各個物件都有相同的某項屬性的時候。比如對於一個存款類,每個例項的利息都是相同的。所以,應該把利息設為存款類的靜態資料成員。這 有兩個好處,第一,不管定義多少個存款類物件,利息資料成員都共享分配在全域性資料區的記憶體,所以節省儲存空間。第二,一旦利息需要改變時,只要改變一次, 則所有存款類物件的利息全改變過來了;
全域性變數相比,使用靜態資料成員有兩個優勢:
靜態資料成員沒有進入程式的全域性名字空間,因此不存在與程式中其它全域性名字衝突的可能性;
可以實現資訊隱藏。靜態資料成員可以是private成員,而全域性變數不能;
靜態成員函式
與靜態資料成員一樣,我們也可以建立一個靜態成員函式,它為類的全部服務而不是為某一個類的具體物件服務。靜態成員函式與靜態資料成員一樣,都是類的內部 實現,屬於類定義的一部分。普通的成員函式一般都隱含了一個this指標,this指標指向類的物件本身,因為普通成員函式總是具體的屬於某個類的具體物件的。通常情況下,this 是預設的。如函式fn()實際上是this->fn()。但是與普通函式相比,靜態成員函式由於不是與任何的物件相聯絡,因此它不具有this指 針。從這個意義上講,它無法訪問屬於類物件的非靜態資料成員,也無法訪問非靜態成員函式,它只能呼叫其餘的靜態成員函式。下面舉個靜態成員函式的例子。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
//Example 6
#include <iostream.h>
class Myclass
{
    public : Myclass(int a,int b,int c);
    static void GetSum(); // 宣告靜態成員函式
    private int a, b, c;
    static int Sum; //宣告靜態資料成員
}
int Myclass::Sum=0; //定義並初始化靜態資料成員
Myclass::Myclass(int a,int b,int c)
{
    this->a = a;
    this->b = b;
    this->c = c;
    Sum += a + b + c; //非靜態成員函式可以訪問靜態資料成員
}
void Myclass::GetSum() //靜態成員函式的實現
{
    // cout<<a<<endl; //錯誤程式碼,a是非靜態資料成員
    cout<<"Sum="<<Sum<<endl;
}
void main()
{
    Myclass M(1,2,3);
    M.GetSum();
    Myclass N(4,5,6);
    N.GetSum();
    Myclass::GetSum();
}
關於靜態成員函式,可以總結為以下幾點:
出現在類體外的函式定義不能指定關鍵字static;
靜態成員之間可以相互訪問,包括靜態成員函式訪問靜態資料成員和訪問靜態成員函式;
非靜態成員函式可以任意地訪問靜態成員函式和靜態資料成員;
靜態成員函式不能訪問非靜態成員函式和非靜態資料成員;
由於沒有this指標的額外開銷,因此靜態成員函式與類的全域性函式相比速度上會有少許的增長;
呼叫靜態成員函式,可以用成員訪問操作符(.)和(->;)為一個類的物件或指向類物件的指標呼叫靜態成員函式,也可以直接使用如下格式:
<;類名>::<;靜態成員函式名>;(<;參數列>;)
呼叫類的靜態成員函式。
作用
static靜態變數宣告符。在宣告它的程式塊,子程式塊或函式內部有效,值保持,在整個程式期間分配儲存器空間,編譯器預設值0。
是C++中很常用的修飾符,它被用來控制變數的儲存方式和可見性。
為什麼要引入static
函式內部定義的變數,在程式執行到它的定義處時,編譯器為它在棧上分配空間,大家知道,函式在棧上分配的空間在此函式執行結束時會釋放掉,這樣就產生了一個問題: 如果想將函式中此變數的值儲存至下一次呼叫時,如何實現? 最容易想到的方法是定義一個全域性的變數,但定義為一個全域性變數有許多缺點,最明顯的缺點是破壞了此變數的訪問範圍(使得在此函式中定義的變數,不僅僅受此函式控制)。
什麼時候用static
需要一個資料物件為整個類而非某個物件服務,同時又力求不破壞類的封裝性,即要求此成員隱藏在類的內部,對外不可見。
內部機制
靜態資料成員要在程式一開始執行時就必須存在。因為函式在程式執行中被呼叫,所以靜態資料成員不能在任何函式內分配空間和初始化。
這樣,它的空間分配有三個可能的地方,一是作為類的外部介面的標頭檔案,那裡有類宣告;二是類定義的內部實現,那裡有類的成員函式定義;三是應用程式的main()函式前的全域性資料宣告和定義處。
靜態資料成員要實際地分配空間,故不能在類的宣告中定義(只能宣告資料成員)。類宣告只宣告一個類的“尺寸和規格”,並不進行實際的記憶體分配,所以在類宣告中寫成定義是錯誤的。它也不能在標頭檔案中類宣告的外部定義,因為那會造成在多個使用該類的原始檔中,對其重複定義。
static被引入以告知編譯器,將變數儲存在程式的靜態儲存區而非棧上空間,靜態
資料成員按定義出現的先後順序依次初始化,注意靜態成員巢狀時,要保證所巢狀的成員已經初始化了。消除時的順序是初始化的反順序。
優勢
可以節省記憶體,因為它是所有物件所公有的,因此,對多個物件來說,靜態資料成員只儲存一處,供所有物件共用。靜態資料成員的值對每個物件都是一樣,但它的值是可以更新的。只要對靜態資料成員的值更新一次,保證所有物件存取更新後的相同的值,這樣可以提高時間效率。
應用格式
引用靜態資料成員時,採用如下格式:
<;類名>::<;靜態成員名>
如果靜態資料成員的訪問許可權允許的話(即public的成員),可在程式中,按上述格式來引用靜態資料成員。
注意事項
⑴類的靜態成員函式是屬於整個類而非類的物件,所以它沒有this指標,這就導致了它僅能訪問類的靜態資料和靜態成員函式。
⑵不能將靜態成員函式定義為虛擬函式。
⑶由於靜態成員宣告於類中,操作於其外,所以對其取地址操作,就多少有些特殊,變數地址是指向其資料型別的指標 ,函式地址型別是一個“nonmember函式指標”。
⑷由於靜態成員函式沒有this指標,所以就差不多等同於nonmember函式,結果就產生了一個意想不到的好處:成為一個callback函式,使得我們得以將C++和C-based X Window系統結合,同時也成功的應用於執行緒函式身上。
⑸static並沒有增加程式的時空開銷,相反她還縮短了子類對父類靜態成員的訪問時間,節省了子類的記憶體空間。
⑹靜態資料成員在<;定義或說明>;時前面加關鍵字static。
⑺靜態資料成員是靜態儲存的,所以必須對它進行初始化。
⑻靜態成員初始化與一般資料成員初始化不同:
初始化在類體外進行,而前面不加static,以免與一般靜態變數或物件相混淆;
初始化時不加該成員的訪問許可權控制符private,public等;
初始化時使用作用域運算子來標明它所屬類;
所以我們得出靜態資料成員初始化的格式:
<;資料型別><;類名>::<;靜態資料成員名>=<;值>
⑼為了防止父類的影響,可以在子類定義一個與父類相同的靜態變數,以遮蔽父類的影響。這裡有一點需要注意:我們說靜態成員為父類和子類共享,但我們有重複定義了靜態成員,這會不會引起錯誤呢?不會,我們的編譯器採用了一種絕妙的手法:name-mangling 用以生成唯一的標誌。在各通訊公司的筆試面試中經常出現的考題就是static的作用及功能。

C語言中

編輯
static 函式內部函式和外部函式
當一個源程式由多個原始檔組成時,C語言根據函式能否被其它原始檔中的函式呼叫,將函式分為內部函式和外部函式。
內部函式
(又稱靜態函式
如果在一個原始檔中定義的函式,只能被本檔案中的函式呼叫,而不能被同一程式其它檔案中的函式呼叫,這種函式稱為內部函式。
定義一個內部函式,只需在函式型別前再加一個“static”關鍵字即可,如下所示:
static 函式型別 函式名(函式參數列){……}
關鍵字“static”,譯成中文就是“靜態的”,所以內部函式又稱靜態函式。但此處“static”的含義不是指儲存方式,而是指對函式的作用域僅侷限於本檔案。
使用內部函式的好處是:不同的人編寫不同的函式時,不用擔心自己定義的函式,是否會與其它檔案中的函式同名,因為同名也沒有關係。
外部函式
外部函式的定義:在定義函式時,如果沒有加關鍵字“static”,或冠以關鍵字“extern”,表示此函式是外部函式:
[extern] 函式型別 函式名(函式參數列){……}
呼叫外部函式時,需要對其進行說明:
[extern] 函式型別 函式名(引數型別表)[,函式名2(引數型別表2)……];
[案例]外部函式應用。
⑴檔案mainf.c
main()
{
extern void input(…),process(…),output(…);
input(…);
process(…);
output(…);
}
⑵檔案subf1.c
……extern void input(……) /*定義外部函式*/{……}
⑶檔案subf2.c
……extern void process(……) /*定義外部 函式*/{……}
⑷檔案subf3.c
……extern void output(……) /*定義外部函式*/{……}靜態區域性變數static的儲存 有時希望函式中的區域性變數的值在函式呼叫結束後不消失而繼續保留原值,即其佔用的儲存單元不釋放,在下一次再呼叫該函式時,該變數已有值(就是上一次函式呼叫結束時的值)。這時就應該指定該區域性變數為“靜態區域性變數”,用關鍵字static進行宣告。用靜態儲存要多佔記憶體(長期佔用不釋放,而不能像動態儲存那樣一個儲存單元可以先後為多個變數使用,節約記憶體),而且降低了程式的可讀性,因此若非必要,不要多用靜態區域性變數。vb中語句
在過程級別中使用,用於宣告變數並分配儲存空間。在整個程式碼執行期間都能保留使用 Static 語句宣告的變數的值。
static語句宣告的變數,與dim語句宣告的變數的主要區別是:前者只能在sub或function過程中使用,在退出sub或function過程後變數的值保留;後者使用在sub或function過程中時,退出sub或function過程後變數的值不保留。
語法Staticvarname[([subscripts])] [As [New]type] [,varname[([subscripts])] [As [New]type]] . . .
Static 語句的語法包含下面部分:
描述
varname 必需的。變數的名稱;遵循標準變數命名約定
subscripts 可選的。陣列變數的維數;最多可以定義 60 維的多維陣列。subscripts 引數使用下面的語法:
[lower To] upper [,[lower To] upper] . . .
如果不顯式指定 lower,則陣列的下界由 Option Base 語句控制。如果沒有 Option Base 語句則下界為 0。
New 可選的。用它可以隱式地建立物件的關鍵字。如果使用 New 宣告物件變數,則在第一次引用該變數時將新建該物件的例項,因此不必使用 Set 語句來對該物件引用賦值。New 關鍵字不能用來宣告任何內部資料型別的變數,也不能用來宣告從屬物件的例項。
type 可選的。變數的資料型別;可以是
Byte、Boolean、Integer、Long、Currency、Single、Double、Decimal(目前尚不支援)、Date、String(對變長的字串)、String * length(對定長的字串)、Object、Variant、使用者定義型別或物件型別。
所宣告的每個變數都要有一個單獨的 As type 子句。
說明
模組的程式碼開始執行後,使用 Static 語句宣告的變數會一直保持其值,直至該模組復位或重新啟動。可以在非靜態的過程中使用 Static 語句顯式宣告只在該過程內可見,但具有與包含該過程定義的模組相同生命期的變數。
可以在過程中使用 Static 語句來宣告在過程呼叫之間仍能保持其值的變數的資料型別。例如,下面的語句宣告瞭一個定長的整型陣列
Static EmployeeNumber(200) As Integer
下面的語句為 worksheet 的新例項宣告瞭一個變數:
Static X As New Worksheet
如果在定義物件變數時沒有使用 New 關鍵字,則在使用該變數之前,必須使用 Set 語句將一個已有的物件賦給這個引用物件的變數。在被賦值之前,所宣告的這個物件變數有一個特定值 Nothing,這個值表示該變數沒有指向任何物件的例項。若在宣告中使用了 New 關鍵字,則在第一次引用物件時將新建一個該物件的例項。
如果不指定資料型別或物件型別,且在模組中沒有使用 Deftype 語句,則按預設情況,定義該變數為 Variant 型別。
注意
Static 語句與 Static 關鍵字很相似,但是針對不同的效果來使用的。如果使用 Static 關鍵字(如 Static Sub CountSales ())來宣告一個過程,則該過程中的所有區域性變數的儲存空間都只分配一次,且這些變數的值在整個程式執行期間都存在。對非靜態過程而言,該過程每次被呼叫時都要為其變數分配儲存空間,當該過程結束時都要釋放其變數的儲存空間。Static 語句則用來在非靜態的過程中宣告特定的變數,以使其在程式執行期間能保持其值。
在初始化變數時,數值變數被初始化為 0,變長的字串被初始化為一個零長度的字串 (""),而定長的字串則用 0 填充。Variant 變數被初始化為 Empty。使用者自定義型別的變數的每個元素作為各自獨立的變數進行初始化。
注意 如果在過程中使用 Static 語句,應和其它的宣告語句(如 Dim)一樣將其放在過程的開始。
作用
static的作用
在C語言中,static的字面意思很容易把我們匯入歧途,其實它的作用有三條。
(1)先來介紹它的第一條也是最重要的一條:隱藏。
當我們同時編譯多個檔案時,所有未加static字首的全域性變數和函式都具有全域性可見性。為理解這句話,我舉例來說明。我們要同時編譯兩個原始檔,一個是a.c,另一個是main.c。
下面是a.c的內容
char a = 'A'; // global variable
void msg() {
printf("Hello\n");
}
下面是main.c的內容
1
2
3
4
5
6
7
int main(void)
{
extern char a; // extern variable must be declared before use
printf("%c ", a);
(void)msg();
return 0;
}
程式的執行結果是:
A Hello
你可能會問:為什麼在a.c中定義的全域性變數a和函式msg能在main.c中使用?前面說過,所有未加static字首的全域性變數和函式都具有全域性可見性,其它的原始檔也能訪問。此例中,a是全域性變數,msg是函式,並且都沒有加static字首,因此對於另外的原始檔main.c是可見的。
如果加了static,就會對其它原始檔隱藏。例如在a和msg的定義前加上static,main.c就看不到它們了。利用這一特性可以在不同的檔案中定義同名函式和同名變數,而不必擔心命名衝突。Static可以用作函式和變數的字首,對於函式來講,static的作用僅限於隱藏,而對於變數,static還有下面兩個作用。
(2)static的第二個作用是保持變數內容的持久。儲存在靜態資料區的變數會在程式剛開始執行時就完成初始化,也是唯一的一次初始化。共有兩種變數儲存在靜態儲存區:全域性變數和static變數,只不過和全域性變數比起來,static可以控制變數的可見範圍,說到底static還是用來隱藏的。雖然這種用法不常見,但我還是舉一個例子。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <stdio.h>
int fun(void)
{
static int count = 10; // 此語句只在函式第一次呼叫時執行,後續函式呼叫此變數的初始值為上次呼叫後的值,每次呼叫後儲存空間不釋放
return count--;
},
int count = 1;
int main(void)
{
printf("global\t\tlocal static\n");
for(; count <= 10; ++count)
printf("%d\t\t%d\n", count, fun());
return 0;
}
程式的執行結果是:
global local static
1 10
2 9
3 8
4 7
5 6
6 5
7 4
8 3
9 2
10 1
(3)static的第三個作用是預設初始化為0。其實全域性變數也具備這一屬性,因為全域性變數也儲存在靜態資料區。在靜態資料區,記憶體中所有的位元組預設值都是0x00,某些時候這一特點可以減少程式設計師的工作量。比如初始化一個稀疏矩陣,我們可以一個一個地把所有元素都置0,然後把不是0的幾個元素賦值。如果定義成靜態的,就省去了一開始置0的操作。再比如要把一個字元陣列當字串來用,但又覺得每次在字元陣列末尾加’\0’太麻煩。如果把字串定義成靜態的,就省去了這個麻煩,因為那裡本來就是’\0’。不妨做個小實驗驗證一下。
1
2
3
4
5
6
7
8
#include <stdio.h>
int a;int main(void)
{
int i;
static char str[10];
printf("integer: %d; string: (begin)%s(end)", a, str);
return 0;
}
程式的執行結果如下
integer: 0; string: (begin)(end)
最後對static的三條作用做一句話總結。首先static的最主要功能是隱藏,其次因為static變數存放在靜態儲存區,所以它具備永續性和預設值0。

JAVA語言中

編輯
有時你希望定義一個類成員,使它的使用完全獨立於該類的任何物件。通常情況下,類成員必須通過它的類的物件訪問,但是可以建立這樣一個成員,它能夠被它自己使用,而不必引用特定的例項。在成員的宣告前面加上關鍵字static(靜態的)就能建立這樣的成員。如果一個成員被宣告為static,它就能夠在它的類的任何物件建立之前被訪問,而不必引用任何物件。你可以將方法和變數都宣告為static。static 成員的最常見的例子是main()。因為在程式開始執行時必須呼叫main() ,所以它被宣告為static。
宣告為static的變數稱為靜態變數類變數。可以直接通過類名引用靜態變數,也可以通過例項名來引用靜態變數,但最好採用前者,因為後者容易混淆靜態變數和一般變數。靜態變數是跟類相關聯的,類的所有例項共同擁有一個靜態變數。
宣告為static的方法稱為靜態方法或類方法。靜態方法可以直接呼叫靜態方法,訪問靜態變數,但是不能直接訪問例項變數和例項方法。靜態方法中不能使用this關鍵字,因為靜態方法不屬於任何一個例項。靜態方法不能被子類的靜態方法覆蓋。
舉例
如果你需要通過計算來初始化你的static變數,你可以宣告一個static塊,Static 塊僅在該類被載入時執行一次。下面的例子顯示的類有一個static方法,一些static變數,以及一個static 初始化塊:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// Demonstrate static variables,methods,and blocks.
class UseStatic{ 
    static int a = 3
    static int b; 
    static void meth(int x) { 
        System.out.println("x = " + x); 
        System.out.println("a = " + a); 
        System.out.println("b = " + b); 
    
    static {
       System.out.println("Static block initialized.");
       b = a * 4;
    }
    public static void main(String args[]) {
      meth(42); 
    }
}
一旦UseStatic 類被裝載,所有的static語句被執行。首先,類屬性變數開始賦值,a被設定為3,b預設初始化為 0 ,接著執行static 塊,執行(列印一條訊息),最後,b被賦值為a*4 或12。然後呼叫main(),main() 呼叫meth() ,把值42傳遞給x。3個println () 語句引用兩個static變數a和b,以及區域性變數x。
注意:在一個static 方法中引用任何例項變數都是非法的。
下面是該程式的輸出:
Static block initialized
.x = 42
a = 3
b = 12
使用 static修飾符宣告屬於型別本身而不是屬於特定物件的靜態成員static修飾符可用於類、欄位、方法、屬性、運算子、事件和建構函式,但不能用於索引器解構函式或類以外的型別。例如,下面的類宣告為static,並且只包含 static方法。
例如:
1
2
3
4
5
6
7
static class CompanyEmployee{
     
     public static string GetCompanyName(string name) { ... }
     
     public static string GetCompanyAddress(string address) { ... }
 
}
一般來說,類中標註了static的函式與變數能在類外直接引用,比如說:
1
String M_string1 =CompanyEmployee.GetCompanyName(M_string2)
而沒有標註static的函式則必須宣告一個類的實體,有實體來引用。比如說:
1
2
3
4
5
6
7
8
static class CompanyEmployee{//靜態類
    public string GetCompanyName(string name) { ... } //沒有Static
    public static string GetCompanyAddress(string address) { ... }
}
CompanyEmployee M_CompE = new CompanyEmployee();
String M_string1 =M_CompE.GetCompanyName(M_string2);//直接引用
 
 

C#語言中

編輯
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MyNamespace
{
    class Program
    {
        public static void Main(string[] args)
        {
            Console.WriteLine("返回陣列的和");
            int[] values = { 1,2,3,4,5};
            int sum = Sum(values);
            Console.WriteLine(sum);
         }
         //計算陣列的和
         static int Sum(int[] valuesValue)
         {
             int sum = 0;
             for (int i = 0; i < valuesValue.Length; i++)
             {
             sum = sum + valuesValue[i];
              }
            return sum;
        }
    }
}

相關文章