簡述
在結構化程序設計中,內存中數據的共享是通過參數, 全局變量實現的;
在面向對象程序設計中函數與數據成員封裝在一起, 數據共享通過類內部數據成員之間的相互訪問, 外部對象則通過靜態成員(即static成員)來共享數據;
接下來通過面向對象敘述static特性
C++中的static
靜態成員
使用關鍵字static修飾的函數/數據成員, 靜態成員屬於整個類, 由同一個類的所有對象所擁有,共享; 一般通過類名進行訪問: 類名::標識符 ;
注: 在類中定義靜態數據成員, 僅僅是對靜態數據成員進行引用性聲明, 必須在類外使用類名限定定義性聲明(即真正的聲明),這時才能進行初始化
#include<iostream>
using namespace std;
class A{
public:
static int count;
A(){
++count;
cout<<"構造函數"<<endl;
}
A(A const& a){
++count;
cout<<"複製構造函數"<<endl;
}
~A(){cout<<"析構函數"<<endl;
count--;
}
static int show(){
return count; //靜態成員函數可以直接訪問該類的靜態數據成員,訪問費靜態數據成員只能通過對象名
}
};
int A::count=0;
void f(){//順帶測試一下靜態生存期
static int j=0;
j+=2;
int i=2;
cout<<i<<" static j="<<j<<endl;
i+=2;
}
int main(){
f();
cout<<"A對象個數"<<A::show()<<endl;//還沒有構造對象的時候,count數爲0
A a;
A b=a;//發生複製構造
A c(b);
A d;
cout<<"A對象個數"<<A::count<<endl; //此時count數爲4
cout<<endl;
f();
return 0;
}
此處做着重說明: 靜態函數不能是虛函數, 虛函數用於動態綁定(通過虛表的索引值進行函數地址的查找, 索引值必須用到this, 所以靜態函數函數不能作爲虛函數)
爲何static成員函數不能爲virtual
1. static成員不屬於任何類對象或類實例,所以即使給此函數加上virutal也是沒有任何意義的。
2. 靜態與非靜態成員函數之間有一個主要的區別。那就是靜態成員函數沒有this指針。
虛函數依靠vptr和vtable來處理。vptr是一個指針,在類的構造函數中創建生成,並且只能用this指針來訪問它,因爲它是類的一個成員,並且vptr指向保存虛函數地址的vtable.
對於靜態成員函數,它沒有this指針,所以無法訪問vptr. 這就是爲何static函數不能爲virtual.
虛函數的調用關係:this -> vptr -> vtable ->virtual function
第二點: 對const成員函數設置爲靜態沒有任何意義, const只是對函數的this指針進行限制, 而靜態函數沒有this指針
Java中的static
Java中的靜態變量(類變量): static修飾, 主要用於修飾類成員方法, 加載優先於對象初始化(static成員在類被加載的時候就被加載了, 加載static成員會優先於), 靜態代碼塊優先於構造方法執行, 被所有對象共享
- 整個類中只有一個值
- 類初始化的同時就被賦值
- 適用於所有類對象都具有的相同屬性,經常需要共享的數據, 系統中的常量值
- 引用格式: 類名.變量名(或者靜態函數名)
靜態方法: 類方法,屬於當前類, 調用直接類名.靜態方法(), 只能是外部靜態數據成員, 靜態方法中不可出現this關鍵字; 靜態方法中不能訪問非靜態成員(包含屬性, this,super, 非靜態方法); 原因在於當前對象未構造, 無屬性,this,super存在, 但是反之即可(對象都創建了, 肯定能訪問)
例:
public class test{
public static void main(String[] args){
System.out.println(A.show());
A a1=new A();
A a2=new A();
A a3=new A();
System.out.println(A.show());
}
}
class A{
public static int i=0;
public A(){i++; System.out.println("構造方法");}
public static int show(){return i;}
}
//結果將顯示0 3,表示構造3個對象
靜態方法調用非靜態時引發的錯誤
public class test{
public void info(){
System.out.println("一般方法");
}
public static void main(String[] args){
info();
}
}
上述操作將出現錯誤靜態上下文引用非靜態變量, main()方法爲static, 當main方法初始化的時候, 對象還未創建, 調用info的對象是this, this還未被創建,對上述操作有如下改進
public static void main(String[] args){
new test().info();
}
注: 當涉及到super時, 效果與this一致;
總結
C++與Java中的static用法具有區別, 但是核心都是static只屬於類, 靜態函數不能調用非靜態變量(包含this,super, 一般成員函數,成員變量), 最主要的原因還是在於this的隱藏, 大多數的出現的靜態調用非靜態主要在於this,super以及在對象還未產生就調用對象的函數